thats odd, but just in case it happens again i want to see it.
[asterisk/asterisk.git] / channels / chan_agent.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19
20 /*! \file
21  * 
22  * \brief Implementation of Agents (proxy channel)
23  *
24  * \author Mark Spencer <markster@digium.com>
25  *
26  * This file is the implementation of Agents modules.
27  * It is a dynamic module that is loaded by Asterisk. 
28  * \par See also
29  * \arg \ref Config_agent
30  *
31  * \ingroup channel_drivers
32  */
33
34 #include "asterisk.h"
35
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37
38 #include <stdio.h>
39 #include <string.h>
40 #include <errno.h>
41 #include <unistd.h>
42 #include <sys/socket.h>
43 #include <stdlib.h>
44 #include <fcntl.h>
45 #include <netdb.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <sys/signal.h>
49
50 #include "asterisk/lock.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/config.h"
53 #include "asterisk/logger.h"
54 #include "asterisk/module.h"
55 #include "asterisk/pbx.h"
56 #include "asterisk/options.h"
57 #include "asterisk/lock.h"
58 #include "asterisk/sched.h"
59 #include "asterisk/io.h"
60 #include "asterisk/rtp.h"
61 #include "asterisk/acl.h"
62 #include "asterisk/callerid.h"
63 #include "asterisk/file.h"
64 #include "asterisk/cli.h"
65 #include "asterisk/app.h"
66 #include "asterisk/musiconhold.h"
67 #include "asterisk/manager.h"
68 #include "asterisk/features.h"
69 #include "asterisk/utils.h"
70 #include "asterisk/causes.h"
71 #include "asterisk/astdb.h"
72 #include "asterisk/devicestate.h"
73 #include "asterisk/monitor.h"
74 #include "asterisk/stringfields.h"
75
76 static const char tdesc[] = "Call Agent Proxy Channel";
77 static const char config[] = "agents.conf";
78
79 static const char app[] = "AgentLogin";
80 static const char app2[] = "AgentCallbackLogin";
81 static const char app3[] = "AgentMonitorOutgoing";
82
83 static const char synopsis[] = "Call agent login";
84 static const char synopsis2[] = "Call agent callback login";
85 static const char synopsis3[] = "Record agent's outgoing call";
86
87 static const char descrip[] =
88 "  AgentLogin([AgentNo][|options]):\n"
89 "Asks the agent to login to the system.  Always returns -1.  While\n"
90 "logged in, the agent can receive calls and will hear a 'beep'\n"
91 "when a new call comes in. The agent can dump the call by pressing\n"
92 "the star key.\n"
93 "The option string may contain zero or more of the following characters:\n"
94 "      's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
95
96 static const char descrip2[] =
97 "  AgentCallbackLogin([AgentNo][|[options][|[exten]@context]]):\n"
98 "Asks the agent to login to the system with callback.\n"
99 "The agent's callback extension is called (optionally with the specified\n"
100 "context).\n"
101 "The option string may contain zero or more of the following characters:\n"
102 "      's' -- silent login - do not announce the login ok segment agent logged in/off\n";
103
104 static const char descrip3[] =
105 "  AgentMonitorOutgoing([options]):\n"
106 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
107 "comparison of the callerid of the current interface and the global variable \n"
108 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
109 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
110 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
111 "\nReturn value:\n"
112 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
113 "the agentid are not specified it'll look for n+101 priority.\n"
114 "\nOptions:\n"
115 "       'd' - make the app return -1 if there is an error condition and there is\n"
116 "             no extension n+101\n"
117 "       'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
118 "       'n' - don't generate the warnings when there is no callerid or the\n"
119 "             agentid is not known.\n"
120 "             It's handy if you want to have one context for agent and non-agent calls.\n";
121
122 static const char mandescr_agents[] =
123 "Description: Will list info about all possible agents.\n"
124 "Variables: NONE\n";
125
126 static const char mandescr_agent_logoff[] =
127 "Description: Sets an agent as no longer logged in.\n"
128 "Variables: (Names marked with * are required)\n"
129 "       *Agent: Agent ID of the agent to log off\n"
130 "       Soft: Set to 'true' to not hangup existing calls\n";
131
132 static const char mandescr_agent_callback_login[] =
133 "Description: Sets an agent as logged in with callback.\n"
134 "Variables: (Names marked with * are required)\n"
135 "       *Agent: Agent ID of the agent to login\n"
136 "       *Exten: Extension to use for callback\n"
137 "       Context: Context to use for callback\n"
138 "       AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
139 "       WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
140
141 static char moh[80] = "default";
142
143 #define AST_MAX_AGENT   80                          /*!< Agent ID or Password max length */
144 #define AST_MAX_BUF     256
145 #define AST_MAX_FILENAME_LEN    256
146
147 static const char pa_family[] = "/Agents";          /*!< Persistent Agents astdb family */
148 #define PA_MAX_LEN 2048                             /*!< The maximum length of each persistent member agent database entry */
149
150 static int persistent_agents = 0;                   /*!< queues.conf [general] option */
151 static void dump_agents(void);
152
153 static ast_group_t group;
154 static int autologoff;
155 static int wrapuptime;
156 static int ackcall;
157 static int endcall;
158 static int multiplelogin = 1;
159 static int autologoffunavail = 0;
160
161 static int maxlogintries = 3;
162 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
163
164 static int recordagentcalls = 0;
165 static char recordformat[AST_MAX_BUF] = "";
166 static char recordformatext[AST_MAX_BUF] = "";
167 static char urlprefix[AST_MAX_BUF] = "";
168 static char savecallsin[AST_MAX_BUF] = "";
169 static int updatecdr = 0;
170 static char beep[AST_MAX_BUF] = "beep";
171
172 #define GETAGENTBYCALLERID      "AGENTBYCALLERID"
173
174 /*! \brief Structure representing an agent.  */
175 struct agent_pvt {
176         ast_mutex_t lock;              /*!< Channel private lock */
177         int dead;                      /*!< Poised for destruction? */
178         int pending;                   /*!< Not a real agent -- just pending a match */
179         int abouttograb;               /*!< About to grab */
180         int autologoff;                /*!< Auto timeout time */
181         int ackcall;                   /*!< ackcall */
182         time_t loginstart;             /*!< When agent first logged in (0 when logged off) */
183         time_t start;                  /*!< When call started */
184         struct timeval lastdisc;       /*!< When last disconnected */
185         int wrapuptime;                /*!< Wrapup time in ms */
186         ast_group_t group;             /*!< Group memberships */
187         int acknowledged;              /*!< Acknowledged */
188         char moh[80];                  /*!< Which music on hold */
189         char agent[AST_MAX_AGENT];     /*!< Agent ID */
190         char password[AST_MAX_AGENT];  /*!< Password for Agent login */
191         char name[AST_MAX_AGENT];
192         ast_mutex_t app_lock;          /**< Synchronization between owning applications */
193         volatile pthread_t owning_app; /**< Owning application thread id */
194         volatile int app_sleep_cond;   /**< Sleep condition for the login app */
195         struct ast_channel *owner;     /**< Agent */
196         char loginchan[80];            /**< channel they logged in from */
197         char logincallerid[80];        /**< Caller ID they had when they logged in */
198         struct ast_channel *chan;      /**< Channel we use */
199         AST_LIST_ENTRY(agent_pvt) list; /**< Next Agent in the linked list. */
200 };
201
202 static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (loaded form agents.conf). */
203
204 #define CHECK_FORMATS(ast, p) do { \
205         if (p->chan) {\
206                 if (ast->nativeformats != p->chan->nativeformats) { \
207                         ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
208                         /* Native formats changed, reset things */ \
209                         ast->nativeformats = p->chan->nativeformats; \
210                         ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
211                         ast_set_read_format(ast, ast->readformat); \
212                         ast_set_write_format(ast, ast->writeformat); \
213                 } \
214                 if (p->chan->readformat != ast->rawreadformat)  \
215                         ast_set_read_format(p->chan, ast->rawreadformat); \
216                 if (p->chan->writeformat != ast->rawwriteformat) \
217                         ast_set_write_format(p->chan, ast->rawwriteformat); \
218         } \
219 } while(0)
220
221 /*! \brief Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
222    properly for a timingfd XXX This might need more work if agents were logged in as agents or other
223    totally impractical combinations XXX */
224
225 #define CLEANUP(ast, p) do { \
226         int x; \
227         if (p->chan) { \
228                 for (x=0;x<AST_MAX_FDS;x++) {\
229                         if (x != AST_TIMING_FD) \
230                                 ast->fds[x] = p->chan->fds[x]; \
231                 } \
232                 ast->fds[AST_AGENT_FD] = p->chan->fds[AST_TIMING_FD]; \
233         } \
234 } while(0)
235
236 /*--- Forward declarations */
237 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
238 static int agent_devicestate(void *data);
239 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
240 static int agent_digit_begin(struct ast_channel *ast, char digit);
241 static int agent_digit_end(struct ast_channel *ast, char digit);
242 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
243 static int agent_hangup(struct ast_channel *ast);
244 static int agent_answer(struct ast_channel *ast);
245 static struct ast_frame *agent_read(struct ast_channel *ast);
246 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
247 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
248 static int agent_sendtext(struct ast_channel *ast, const char *text);
249 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
250 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
251 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
252 static void set_agentbycallerid(const char *callerid, const char *agent);
253
254 /*! \brief Channel interface description for PBX integration */
255 static const struct ast_channel_tech agent_tech = {
256         .type = "Agent",
257         .description = tdesc,
258         .capabilities = -1,
259         .requester = agent_request,
260         .devicestate = agent_devicestate,
261         .send_digit_begin = agent_digit_begin,
262         .send_digit_end = agent_digit_end,
263         .call = agent_call,
264         .hangup = agent_hangup,
265         .answer = agent_answer,
266         .read = agent_read,
267         .write = agent_write,
268         .write_video = agent_write,
269         .send_html = agent_sendhtml,
270         .send_text = agent_sendtext,
271         .exception = agent_read,
272         .indicate = agent_indicate,
273         .fixup = agent_fixup,
274         .bridged_channel = agent_bridgedchannel,
275 };
276
277 /*!
278  * Adds an agent to the global list of agents.
279  *
280  * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
281  * \param pending If it is pending or not.
282  * @return The just created agent.
283  * \sa agent_pvt, agents.
284  */
285 static struct agent_pvt *add_agent(char *agent, int pending)
286 {
287         char *parse;
288         AST_DECLARE_APP_ARGS(args,
289                 AST_APP_ARG(agt);
290                 AST_APP_ARG(password);
291                 AST_APP_ARG(name);
292         );
293         char *password = NULL;
294         char *name = NULL;
295         char *agt = NULL;
296         struct agent_pvt *p;
297
298         parse = ast_strdupa(agent);
299
300         /* Extract username (agt), password and name from agent (args). */
301         AST_NONSTANDARD_APP_ARGS(args, parse, ',');
302
303         if(args.argc == 0) {
304                 ast_log(LOG_WARNING, "A blank agent line!\n");
305                 return NULL;
306         }
307
308         if(ast_strlen_zero(args.agt) ) {
309                 ast_log(LOG_WARNING, "An agent line with no agentid!\n");
310                 return NULL;
311         } else
312                 agt = args.agt;
313
314         if(!ast_strlen_zero(args.password)) {
315                 password = args.password;
316                 while (*password && *password < 33) password++;
317         }
318         if(!ast_strlen_zero(args.name)) {
319                 name = args.name;
320                 while (*name && *name < 33) name++;
321         }
322         
323         /* Are we searching for the agent here ? To see if it exists already ? */
324         AST_LIST_TRAVERSE(&agents, p, list) {
325                 if (!pending && !strcmp(p->agent, agt))
326                         break;
327         }
328         if (!p) {
329                 // Build the agent.
330                 if (!(p = ast_calloc(1, sizeof(*p))))
331                         return NULL;
332                 ast_copy_string(p->agent, agt, sizeof(p->agent));
333                 ast_mutex_init(&p->lock);
334                 ast_mutex_init(&p->app_lock);
335                 p->owning_app = (pthread_t) -1;
336                 p->app_sleep_cond = 1;
337                 p->group = group;
338                 p->pending = pending;
339                 AST_LIST_INSERT_TAIL(&agents, p, list);
340         }
341         
342         ast_copy_string(p->password, password ? password : "", sizeof(p->password));
343         ast_copy_string(p->name, name ? name : "", sizeof(p->name));
344         ast_copy_string(p->moh, moh, sizeof(p->moh));
345         p->ackcall = ackcall;
346         p->autologoff = autologoff;
347
348         /* If someone reduces the wrapuptime and reloads, we want it
349          * to change the wrapuptime immediately on all calls */
350         if (p->wrapuptime > wrapuptime) {
351                 struct timeval now = ast_tvnow();
352                 /* XXX check what is this exactly */
353
354                 /* We won't be pedantic and check the tv_usec val */
355                 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
356                         p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
357                         p->lastdisc.tv_usec = now.tv_usec;
358                 }
359         }
360         p->wrapuptime = wrapuptime;
361
362         if (pending)
363                 p->dead = 1;
364         else
365                 p->dead = 0;
366         return p;
367 }
368
369 /*!
370  * Deletes an agent after doing some clean up.
371  * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
372  * \param p Agent to be deleted.
373  * \returns Always 0.
374  */
375 static int agent_cleanup(struct agent_pvt *p)
376 {
377         struct ast_channel *chan = p->owner;
378         p->owner = NULL;
379         chan->tech_pvt = NULL;
380         p->app_sleep_cond = 1;
381         /* Release ownership of the agent to other threads (presumably running the login app). */
382         ast_mutex_unlock(&p->app_lock);
383         if (chan)
384                 ast_channel_free(chan);
385         if (p->dead) {
386                 ast_mutex_destroy(&p->lock);
387                 ast_mutex_destroy(&p->app_lock);
388                 free(p);
389         }
390         return 0;
391 }
392
393 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
394
395 static int agent_answer(struct ast_channel *ast)
396 {
397         ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
398         return -1;
399 }
400
401 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
402 {
403         char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
404         char filename[AST_MAX_BUF];
405         int res = -1;
406         if (!p)
407                 return -1;
408         if (!ast->monitor) {
409                 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
410                 /* substitute . for - */
411                 if ((pointer = strchr(filename, '.')))
412                         *pointer = '-';
413                 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
414                 ast_monitor_start(ast, recordformat, tmp, needlock);
415                 ast_monitor_setjoinfiles(ast, 1);
416                 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
417 #if 0
418                 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
419 #endif
420                 if (!ast->cdr)
421                         ast->cdr = ast_cdr_alloc();
422                 ast_cdr_setuserfield(ast, tmp2);
423                 res = 0;
424         } else
425                 ast_log(LOG_ERROR, "Recording already started on that call.\n");
426         return res;
427 }
428
429 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
430 {
431         return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
432 }
433
434 static struct ast_frame *agent_read(struct ast_channel *ast)
435 {
436         struct agent_pvt *p = ast->tech_pvt;
437         struct ast_frame *f = NULL;
438         static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
439         const char *status;
440         ast_mutex_lock(&p->lock); 
441         CHECK_FORMATS(ast, p);
442         if (p->chan) {
443                 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
444                 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
445                 f = ast_read(p->chan);
446         } else
447                 f = &ast_null_frame;
448         if (!f) {
449                 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
450                 if (p->chan) {
451                         p->chan->_bridge = NULL;
452                         /* Note that we don't hangup if it's not a callback because Asterisk will do it
453                            for us when the PBX instance that called login finishes */
454                         if (!ast_strlen_zero(p->loginchan)) {
455                                 if (p->chan)
456                                         ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
457
458                                 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
459                                 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
460                                         long logintime = time(NULL) - p->loginstart;
461                                         p->loginstart = 0;
462                                         ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
463                                         agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
464                                 }
465                                 ast_hangup(p->chan);
466                                 if (p->wrapuptime && p->acknowledged)
467                                         p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
468                         }
469                         p->chan = NULL;
470                         p->acknowledged = 0;
471                 }
472         } else {
473                 /* if acknowledgement is not required, and the channel is up, we may have missed
474                    an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
475                 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
476                         p->acknowledged = 1;
477                 switch (f->frametype) {
478                 case AST_FRAME_CONTROL:
479                         if (f->subclass == AST_CONTROL_ANSWER) {
480                                 if (p->ackcall) {
481                                         if (option_verbose > 2)
482                                                 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
483                                         /* Don't pass answer along */
484                                         ast_frfree(f);
485                                         f = &ast_null_frame;
486                                 } else {
487                                         p->acknowledged = 1;
488                                         /* Use the builtin answer frame for the 
489                                            recording start check below. */
490                                         ast_frfree(f);
491                                         f = &answer_frame;
492                                 }
493                         }
494                         break;
495                 case AST_FRAME_DTMF_BEGIN:
496                 case AST_FRAME_DTMF_END:
497                         if (!p->acknowledged && (f->subclass == '#')) {
498                                 if (option_verbose > 2)
499                                         ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
500                                 p->acknowledged = 1;
501                                 ast_frfree(f);
502                                 f = &answer_frame;
503                         } else if (f->subclass == '*' && endcall) {
504                                 /* terminates call */
505                                 ast_frfree(f);
506                                 f = NULL;
507                         }
508                         break;
509                 case AST_FRAME_VOICE:
510                 case AST_FRAME_VIDEO:
511                         /* don't pass voice or video until the call is acknowledged */
512                         if (!p->acknowledged) {
513                                 ast_frfree(f);
514                                 f = &ast_null_frame;
515                         }
516                 default:
517                         /* pass everything else on through */
518                         break;
519                 }
520         }
521
522         CLEANUP(ast,p);
523         if (p->chan && !p->chan->_bridge) {
524                 if (strcasecmp(p->chan->tech->type, "Local")) {
525                         p->chan->_bridge = ast;
526                         if (p->chan)
527                                 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
528                 }
529         }
530         ast_mutex_unlock(&p->lock);
531         if (recordagentcalls && f == &answer_frame)
532                 agent_start_monitoring(ast,0);
533         return f;
534 }
535
536 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
537 {
538         struct agent_pvt *p = ast->tech_pvt;
539         int res = -1;
540         ast_mutex_lock(&p->lock);
541         if (p->chan) 
542                 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
543         ast_mutex_unlock(&p->lock);
544         return res;
545 }
546
547 static int agent_sendtext(struct ast_channel *ast, const char *text)
548 {
549         struct agent_pvt *p = ast->tech_pvt;
550         int res = -1;
551         ast_mutex_lock(&p->lock);
552         if (p->chan) 
553                 res = ast_sendtext(p->chan, text);
554         ast_mutex_unlock(&p->lock);
555         return res;
556 }
557
558 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
559 {
560         struct agent_pvt *p = ast->tech_pvt;
561         int res = -1;
562         CHECK_FORMATS(ast, p);
563         ast_mutex_lock(&p->lock);
564         if (!p->chan) 
565                 res = 0;
566         else {
567                 if ((f->frametype != AST_FRAME_VOICE) ||
568                     (f->frametype != AST_FRAME_VIDEO) ||
569                     (f->subclass == p->chan->writeformat)) {
570                         res = ast_write(p->chan, f);
571                 } else {
572                         ast_log(LOG_DEBUG, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
573                                 f->frametype == AST_FRAME_VOICE ? "audio" : "video",
574                                 ast->name, p->chan->name);
575                         res = 0;
576                 }
577         }
578         CLEANUP(ast, p);
579         ast_mutex_unlock(&p->lock);
580         return res;
581 }
582
583 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
584 {
585         struct agent_pvt *p = newchan->tech_pvt;
586         ast_mutex_lock(&p->lock);
587         if (p->owner != oldchan) {
588                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
589                 ast_mutex_unlock(&p->lock);
590                 return -1;
591         }
592         p->owner = newchan;
593         ast_mutex_unlock(&p->lock);
594         return 0;
595 }
596
597 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
598 {
599         struct agent_pvt *p = ast->tech_pvt;
600         int res = -1;
601         ast_mutex_lock(&p->lock);
602         if (p->chan)
603                 res = ast_indicate_data(p->chan, condition, data, datalen);
604         else
605                 res = 0;
606         ast_mutex_unlock(&p->lock);
607         return res;
608 }
609
610 static int agent_digit_begin(struct ast_channel *ast, char digit)
611 {
612         struct agent_pvt *p = ast->tech_pvt;
613         int res = -1;
614         ast_mutex_lock(&p->lock);
615         ast_senddigit_begin(p->chan, digit);
616         ast_mutex_unlock(&p->lock);
617         return res;
618 }
619
620 static int agent_digit_end(struct ast_channel *ast, char digit)
621 {
622         struct agent_pvt *p = ast->tech_pvt;
623         int res = -1;
624         ast_mutex_lock(&p->lock);
625         ast_senddigit_end(p->chan, digit);
626         ast_mutex_unlock(&p->lock);
627         return res;
628 }
629
630 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
631 {
632         struct agent_pvt *p = ast->tech_pvt;
633         int res = -1;
634         int newstate=0;
635         ast_mutex_lock(&p->lock);
636         p->acknowledged = 0;
637         if (!p->chan) {
638                 if (p->pending) {
639                         ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
640                         newstate = AST_STATE_DIALING;
641                         res = 0;
642                 } else {
643                         ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
644                         res = -1;
645                 }
646                 ast_mutex_unlock(&p->lock);
647                 if (newstate)
648                         ast_setstate(ast, newstate);
649                 return res;
650         } else if (!ast_strlen_zero(p->loginchan)) {
651                 time(&p->start);
652                 /* Call on this agent */
653                 if (option_verbose > 2)
654                         ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
655                 ast_set_callerid(p->chan,
656                         ast->cid.cid_num, ast->cid.cid_name, NULL);
657                 ast_channel_inherit_variables(ast, p->chan);
658                 res = ast_call(p->chan, p->loginchan, 0);
659                 CLEANUP(ast,p);
660                 ast_mutex_unlock(&p->lock);
661                 return res;
662         }
663         ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
664         if (option_debug > 2)
665                 ast_log(LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
666         res = ast_streamfile(p->chan, beep, p->chan->language);
667         if (option_debug > 2)
668                 ast_log(LOG_DEBUG, "Played beep, result '%d'\n", res);
669         if (!res) {
670                 res = ast_waitstream(p->chan, "");
671                 if (option_debug > 2)
672                         ast_log(LOG_DEBUG, "Waited for stream, result '%d'\n", res);
673         }
674         if (!res) {
675                 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
676                 if (option_debug > 2)
677                         ast_log(LOG_DEBUG, "Set read format, result '%d'\n", res);
678                 if (res)
679                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
680         } else {
681                 /* Agent hung-up */
682                 p->chan = NULL;
683         }
684
685         if (!res) {
686                 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
687                 if (option_debug > 2)
688                         ast_log(LOG_DEBUG, "Set write format, result '%d'\n", res);
689                 if (res)
690                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
691         }
692         if(!res) {
693                 /* Call is immediately up, or might need ack */
694                 if (p->ackcall > 1)
695                         newstate = AST_STATE_RINGING;
696                 else {
697                         newstate = AST_STATE_UP;
698                         if (recordagentcalls)
699                                 agent_start_monitoring(ast, 0);
700                         p->acknowledged = 1;
701                 }
702                 res = 0;
703         }
704         CLEANUP(ast, p);
705         ast_mutex_unlock(&p->lock);
706         if (newstate)
707                 ast_setstate(ast, newstate);
708         return res;
709 }
710
711 /*! \brief store/clear the global variable that stores agentid based on the callerid */
712 static void set_agentbycallerid(const char *callerid, const char *agent)
713 {
714         char buf[AST_MAX_BUF];
715
716         /* if there is no Caller ID, nothing to do */
717         if (ast_strlen_zero(callerid))
718                 return;
719
720         snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
721         pbx_builtin_setvar_helper(NULL, buf, agent);
722 }
723
724 static int agent_hangup(struct ast_channel *ast)
725 {
726         struct agent_pvt *p = ast->tech_pvt;
727         int howlong = 0;
728         const char *status;
729         ast_mutex_lock(&p->lock);
730         p->owner = NULL;
731         ast->tech_pvt = NULL;
732         p->app_sleep_cond = 1;
733         p->acknowledged = 0;
734
735         /* if they really are hung up then set start to 0 so the test
736          * later if we're called on an already downed channel
737          * doesn't cause an agent to be logged out like when
738          * agent_request() is followed immediately by agent_hangup()
739          * as in apps/app_chanisavail.c:chanavail_exec()
740          */
741
742         if (option_debug)
743                 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
744         if (p->start && (ast->_state != AST_STATE_UP)) {
745                 howlong = time(NULL) - p->start;
746                 p->start = 0;
747         } else if (ast->_state == AST_STATE_RESERVED) 
748                 howlong = 0;
749         else
750                 p->start = 0; 
751         if (p->chan) {
752                 p->chan->_bridge = NULL;
753                 /* If they're dead, go ahead and hang up on the agent now */
754                 if (!ast_strlen_zero(p->loginchan)) {
755                         /* Store last disconnect time */
756                         if (p->wrapuptime)
757                                 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
758                         else
759                                 p->lastdisc = ast_tv(0,0);
760                         if (p->chan) {
761                                 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
762                                 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
763                                         long logintime = time(NULL) - p->loginstart;
764                                         p->loginstart = 0;
765                                         ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
766                                         agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
767                                 }
768                                 /* Recognize the hangup and pass it along immediately */
769                                 ast_hangup(p->chan);
770                                 p->chan = NULL;
771                         }
772                         ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
773                         if (howlong  && p->autologoff && (howlong > p->autologoff)) {
774                                 long logintime = time(NULL) - p->loginstart;
775                                 p->loginstart = 0;
776                                 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
777                                 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
778                         }
779                 } else if (p->dead) {
780                         ast_channel_lock(p->chan);
781                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
782                         ast_channel_unlock(p->chan);
783                 } else if (p->loginstart) {
784                         ast_channel_lock(p->chan);
785                         ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
786                                 S_OR(p->moh, NULL),
787                                 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
788                         ast_channel_unlock(p->chan);
789                 }
790         }
791         ast_mutex_unlock(&p->lock);
792         /* Only register a device state change if the agent is still logged in */
793         if (p->loginstart)
794                 ast_device_state_changed("Agent/%s", p->agent);
795
796         if (p->pending) {
797                 AST_LIST_LOCK(&agents);
798                 AST_LIST_REMOVE(&agents, p, list);
799                 AST_LIST_UNLOCK(&agents);
800         }
801         if (p->abouttograb) {
802                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
803                    kill it later */
804                 p->abouttograb = 0;
805         } else if (p->dead) {
806                 ast_mutex_destroy(&p->lock);
807                 ast_mutex_destroy(&p->app_lock);
808                 free(p);
809         } else {
810                 if (p->chan) {
811                         /* Not dead -- check availability now */
812                         ast_mutex_lock(&p->lock);
813                         /* Store last disconnect time */
814                         p->lastdisc = ast_tvnow();
815                         ast_mutex_unlock(&p->lock);
816                 }
817                 /* Release ownership of the agent to other threads (presumably running the login app). */
818                 ast_mutex_unlock(&p->app_lock);
819         }
820         return 0;
821 }
822
823 static int agent_cont_sleep( void *data )
824 {
825         struct agent_pvt *p;
826         int res;
827
828         p = (struct agent_pvt *)data;
829
830         ast_mutex_lock(&p->lock);
831         res = p->app_sleep_cond;
832         if (p->lastdisc.tv_sec) {
833                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 
834                         res = 1;
835         }
836         ast_mutex_unlock(&p->lock);
837
838         if(option_debug > 4 && !res )
839                 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
840
841         return res;
842 }
843
844 static int agent_ack_sleep(void *data)
845 {
846         struct agent_pvt *p;
847         int res=0;
848         int to = 1000;
849         struct ast_frame *f;
850
851         /* Wait a second and look for something */
852
853         p = (struct agent_pvt *) data;
854         if (!p->chan) 
855                 return -1;
856
857         for(;;) {
858                 to = ast_waitfor(p->chan, to);
859                 if (to < 0) 
860                         return -1;
861                 if (!to) 
862                         return 0;
863                 f = ast_read(p->chan);
864                 if (!f) 
865                         return -1;
866                 if (f->frametype == AST_FRAME_DTMF)
867                         res = f->subclass;
868                 else
869                         res = 0;
870                 ast_frfree(f);
871                 ast_mutex_lock(&p->lock);
872                 if (!p->app_sleep_cond) {
873                         ast_mutex_unlock(&p->lock);
874                         return 0;
875                 } else if (res == '#') {
876                         ast_mutex_unlock(&p->lock);
877                         return 1;
878                 }
879                 ast_mutex_unlock(&p->lock);
880                 res = 0;
881         }
882         return res;
883 }
884
885 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
886 {
887         struct agent_pvt *p = bridge->tech_pvt;
888         struct ast_channel *ret = NULL;
889
890         if (p) {
891                 if (chan == p->chan)
892                         ret = bridge->_bridge;
893                 else if (chan == bridge->_bridge)
894                         ret = p->chan;
895         }
896
897         if (option_debug)
898                 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
899         return ret;
900 }
901
902 /*! \brief Create new agent channel */
903 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
904 {
905         struct ast_channel *tmp;
906 #if 0
907         if (!p->chan) {
908                 ast_log(LOG_WARNING, "No channel? :(\n");
909                 return NULL;
910         }
911 #endif  
912         tmp = ast_channel_alloc(0);
913         if (!tmp) {
914                 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
915                 return NULL;
916         }
917
918         tmp->tech = &agent_tech;
919         if (p->chan) {
920                 tmp->nativeformats = p->chan->nativeformats;
921                 tmp->writeformat = p->chan->writeformat;
922                 tmp->rawwriteformat = p->chan->writeformat;
923                 tmp->readformat = p->chan->readformat;
924                 tmp->rawreadformat = p->chan->readformat;
925                 ast_string_field_set(tmp, language, p->chan->language);
926                 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
927                 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
928                 /* XXX Is this really all we copy form the originating channel?? */
929         } else {
930                 tmp->nativeformats = AST_FORMAT_SLINEAR;
931                 tmp->writeformat = AST_FORMAT_SLINEAR;
932                 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
933                 tmp->readformat = AST_FORMAT_SLINEAR;
934                 tmp->rawreadformat = AST_FORMAT_SLINEAR;
935         }
936         if (p->pending)
937                 ast_string_field_build(tmp, name, "Agent/P%s-%d", p->agent, ast_random() & 0xffff);
938         else
939                 ast_string_field_build(tmp, name, "Agent/%s", p->agent);
940         /* Safe, agentlock already held */
941         ast_setstate(tmp, state);
942         tmp->tech_pvt = p;
943         p->owner = tmp;
944         /* XXX: this needs fixing */
945 #if 0
946         ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
947 #endif
948         ast_update_use_count();
949         tmp->priority = 1;
950         /* Wake up and wait for other applications (by definition the login app)
951          * to release this channel). Takes ownership of the agent channel
952          * to this thread only.
953          * For signalling the other thread, ast_queue_frame is used until we
954          * can safely use signals for this purpose. The pselect() needs to be
955          * implemented in the kernel for this.
956          */
957         p->app_sleep_cond = 0;
958         if(ast_mutex_trylock(&p->app_lock)) {
959                 if (p->chan) {
960                         ast_queue_frame(p->chan, &ast_null_frame);
961                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
962                         ast_mutex_lock(&p->app_lock);
963                         ast_mutex_lock(&p->lock);
964                 } else {
965                         ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
966                         p->owner = NULL;
967                         tmp->tech_pvt = NULL;
968                         p->app_sleep_cond = 1;
969                         ast_channel_free( tmp );
970                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
971                         ast_mutex_unlock(&p->app_lock);
972                         return NULL;
973                 }
974         }
975         p->owning_app = pthread_self();
976         /* After the above step, there should not be any blockers. */
977         if (p->chan) {
978                 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
979                         ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
980                         CRASH;
981                 }
982                 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
983         }
984         return tmp;
985 }
986
987
988 /*!
989  * Read configuration data. The file named agents.conf.
990  *
991  * \returns Always 0, or so it seems.
992  */
993 static int read_agent_config(void)
994 {
995         struct ast_config *cfg;
996         struct ast_variable *v;
997         struct agent_pvt *p;
998         char *general_val;
999
1000         group = 0;
1001         autologoff = 0;
1002         wrapuptime = 0;
1003         ackcall = 0;
1004         endcall = 1;
1005         cfg = ast_config_load(config);
1006         if (!cfg) {
1007                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1008                 return 0;
1009         }
1010         AST_LIST_LOCK(&agents);
1011         AST_LIST_TRAVERSE(&agents, p, list) {
1012                 p->dead = 1;
1013         }
1014         strcpy(moh, "default");
1015         /* set the default recording values */
1016         recordagentcalls = 0;
1017         strcpy(recordformat, "wav");
1018         strcpy(recordformatext, "wav");
1019         urlprefix[0] = '\0';
1020         savecallsin[0] = '\0';
1021
1022         /* Read in [general] section for persistence */
1023         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1024                 persistent_agents = ast_true(general_val);
1025         multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1026
1027         /* Read in the [agents] section */
1028         v = ast_variable_browse(cfg, "agents");
1029         while(v) {
1030                 /* Create the interface list */
1031                 if (!strcasecmp(v->name, "agent")) {
1032                         add_agent(v->value, 0);
1033                 } else if (!strcasecmp(v->name, "group")) {
1034                         group = ast_get_group(v->value);
1035                 } else if (!strcasecmp(v->name, "autologoff")) {
1036                         autologoff = atoi(v->value);
1037                         if (autologoff < 0)
1038                                 autologoff = 0;
1039                 } else if (!strcasecmp(v->name, "ackcall")) {
1040                         if (!strcasecmp(v->value, "always"))
1041                                 ackcall = 2;
1042                         else if (ast_true(v->value))
1043                                 ackcall = 1;
1044                         else
1045                                 ackcall = 0;
1046                 } else if (!strcasecmp(v->name, "endcall")) {
1047                         endcall = ast_true(v->value);
1048                 } else if (!strcasecmp(v->name, "wrapuptime")) {
1049                         wrapuptime = atoi(v->value);
1050                         if (wrapuptime < 0)
1051                                 wrapuptime = 0;
1052                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1053                         maxlogintries = atoi(v->value);
1054                         if (maxlogintries < 0)
1055                                 maxlogintries = 0;
1056                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1057                         strcpy(agentgoodbye,v->value);
1058                 } else if (!strcasecmp(v->name, "musiconhold")) {
1059                         ast_copy_string(moh, v->value, sizeof(moh));
1060                 } else if (!strcasecmp(v->name, "updatecdr")) {
1061                         if (ast_true(v->value))
1062                                 updatecdr = 1;
1063                         else
1064                                 updatecdr = 0;
1065                 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1066                         if (ast_true(v->value))
1067                                 autologoffunavail = 1;
1068                         else
1069                                 autologoffunavail = 0;
1070                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1071                         recordagentcalls = ast_true(v->value);
1072                 } else if (!strcasecmp(v->name, "recordformat")) {
1073                         ast_copy_string(recordformat, v->value, sizeof(recordformat));
1074                         if (!strcasecmp(v->value, "wav49"))
1075                                 strcpy(recordformatext, "WAV");
1076                         else
1077                                 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1078                 } else if (!strcasecmp(v->name, "urlprefix")) {
1079                         ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1080                         if (urlprefix[strlen(urlprefix) - 1] != '/')
1081                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1082                 } else if (!strcasecmp(v->name, "savecallsin")) {
1083                         if (v->value[0] == '/')
1084                                 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1085                         else
1086                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1087                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1088                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1089                 } else if (!strcasecmp(v->name, "custom_beep")) {
1090                         ast_copy_string(beep, v->value, sizeof(beep));
1091                 }
1092                 v = v->next;
1093         }
1094         AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1095                 if (p->dead) {
1096                         AST_LIST_REMOVE_CURRENT(&agents, list);
1097                         /* Destroy if  appropriate */
1098                         if (!p->owner) {
1099                                 if (!p->chan) {
1100                                         ast_mutex_destroy(&p->lock);
1101                                         ast_mutex_destroy(&p->app_lock);
1102                                         free(p);
1103                                 } else {
1104                                         /* Cause them to hang up */
1105                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1106                                 }
1107                         }
1108                 }
1109         }
1110         AST_LIST_TRAVERSE_SAFE_END
1111         AST_LIST_UNLOCK(&agents);
1112         ast_config_destroy(cfg);
1113         return 1;
1114 }
1115
1116 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1117 {
1118         struct ast_channel *chan=NULL, *parent=NULL;
1119         struct agent_pvt *p;
1120         int res;
1121
1122         if (option_debug)
1123                 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1124         if (needlock)
1125                 AST_LIST_LOCK(&agents);
1126         AST_LIST_TRAVERSE(&agents, p, list) {
1127                 if (p == newlyavailable) {
1128                         continue;
1129                 }
1130                 ast_mutex_lock(&p->lock);
1131                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1132                         if (option_debug)
1133                                 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1134                         /* We found a pending call, time to merge */
1135                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
1136                         parent = p->owner;
1137                         p->abouttograb = 1;
1138                         ast_mutex_unlock(&p->lock);
1139                         break;
1140                 }
1141                 ast_mutex_unlock(&p->lock);
1142         }
1143         if (needlock)
1144                 AST_LIST_UNLOCK(&agents);
1145         if (parent && chan)  {
1146                 if (newlyavailable->ackcall > 1) {
1147                         /* Don't do beep here */
1148                         res = 0;
1149                 } else {
1150                         if (option_debug > 2)
1151                                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1152                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1153                         if (option_debug > 2)
1154                                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1155                         if (!res) {
1156                                 res = ast_waitstream(newlyavailable->chan, "");
1157                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1158                         }
1159                 }
1160                 if (!res) {
1161                         /* Note -- parent may have disappeared */
1162                         if (p->abouttograb) {
1163                                 newlyavailable->acknowledged = 1;
1164                                 /* Safe -- agent lock already held */
1165                                 ast_setstate(parent, AST_STATE_UP);
1166                                 ast_setstate(chan, AST_STATE_UP);
1167                                 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1168                                 /* Go ahead and mark the channel as a zombie so that masquerade will
1169                                    destroy it for us, and we need not call ast_hangup */
1170                                 ast_mutex_lock(&parent->lock);
1171                                 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1172                                 ast_channel_masquerade(parent, chan);
1173                                 ast_mutex_unlock(&parent->lock);
1174                                 p->abouttograb = 0;
1175                         } else {
1176                                 if (option_debug)
1177                                         ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1178                                 agent_cleanup(newlyavailable);
1179                         }
1180                 } else {
1181                         if (option_debug)
1182                                 ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
1183                         agent_cleanup(newlyavailable);
1184                 }
1185         }
1186         return 0;
1187 }
1188
1189 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1190 {
1191         struct agent_pvt *p;
1192         int res=0;
1193
1194         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1195         if (needlock)
1196                 AST_LIST_LOCK(&agents);
1197         AST_LIST_TRAVERSE(&agents, p, list) {
1198                 if (p == newlyavailable) {
1199                         continue;
1200                 }
1201                 ast_mutex_lock(&p->lock);
1202                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1203                         if (option_debug)
1204                                 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1205                         ast_mutex_unlock(&p->lock);
1206                         break;
1207                 }
1208                 ast_mutex_unlock(&p->lock);
1209         }
1210         if (needlock)
1211                 AST_LIST_UNLOCK(&agents);
1212         if (p) {
1213                 ast_mutex_unlock(&newlyavailable->lock);
1214                 if (option_debug > 2)
1215                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1216                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1217                 if (option_debug > 2)
1218                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1219                 if (!res) {
1220                         res = ast_waitstream(newlyavailable->chan, "");
1221                         if (option_debug)
1222                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1223                 }
1224                 ast_mutex_lock(&newlyavailable->lock);
1225         }
1226         return res;
1227 }
1228
1229 /* return 1 if multiple login is fine, 0 if it is not and we find a match, -1 if multiplelogin is not allowed and we don't find a match. */
1230 static int allow_multiple_login(char *chan, char *context)
1231 {
1232         struct agent_pvt *p;
1233         char loginchan[80];
1234
1235         if(multiplelogin)
1236                 return 1;
1237         if(!chan) 
1238                 return 0;
1239
1240         snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
1241         
1242         AST_LIST_TRAVERSE(&agents, p, list) {
1243                 if(!strcasecmp(chan, p->loginchan))
1244                         return 0;
1245         }
1246         return -1;
1247 }
1248
1249 /*! \brief Part of the Asterisk PBX interface */
1250 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1251 {
1252         struct agent_pvt *p;
1253         struct ast_channel *chan = NULL;
1254         char *s;
1255         ast_group_t groupmatch;
1256         int groupoff;
1257         int waitforagent=0;
1258         int hasagent = 0;
1259         struct timeval tv;
1260
1261         s = data;
1262         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1263                 groupmatch = (1 << groupoff);
1264         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1265                 groupmatch = (1 << groupoff);
1266                 waitforagent = 1;
1267         } else 
1268                 groupmatch = 0;
1269
1270         /* Check actual logged in agents first */
1271         AST_LIST_LOCK(&agents);
1272         AST_LIST_TRAVERSE(&agents, p, list) {
1273                 ast_mutex_lock(&p->lock);
1274                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1275                     ast_strlen_zero(p->loginchan)) {
1276                         if (p->chan)
1277                                 hasagent++;
1278                         if (!p->lastdisc.tv_sec) {
1279                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1280                                 if (!p->owner && p->chan) {
1281                                         /* Fixed agent */
1282                                         chan = agent_new(p, AST_STATE_DOWN);
1283                                 }
1284                                 if (chan) {
1285                                         ast_mutex_unlock(&p->lock);
1286                                         break;
1287                                 }
1288                         }
1289                 }
1290                 ast_mutex_unlock(&p->lock);
1291         }
1292         if (!p) {
1293                 AST_LIST_TRAVERSE(&agents, p, list) {
1294                         ast_mutex_lock(&p->lock);
1295                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1296                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1297                                         hasagent++;
1298                                 tv = ast_tvnow();
1299 #if 0
1300                                 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1301 #endif
1302                                 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1303                                         p->lastdisc = ast_tv(0, 0);
1304                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1305                                         if (!p->owner && p->chan) {
1306                                                 /* Could still get a fixed agent */
1307                                                 chan = agent_new(p, AST_STATE_DOWN);
1308                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1309                                                 /* Adjustable agent */
1310                                                 p->chan = ast_request("Local", format, p->loginchan, cause);
1311                                                 if (p->chan)
1312                                                         chan = agent_new(p, AST_STATE_DOWN);
1313                                         }
1314                                         if (chan) {
1315                                                 ast_mutex_unlock(&p->lock);
1316                                                 break;
1317                                         }
1318                                 }
1319                         }
1320                         ast_mutex_unlock(&p->lock);
1321                 }
1322         }
1323
1324         if (!chan && waitforagent) {
1325                 /* No agent available -- but we're requesting to wait for one.
1326                    Allocate a place holder */
1327                 if (hasagent) {
1328                         if (option_debug)
1329                                 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1330                         p = add_agent(data, 1);
1331                         p->group = groupmatch;
1332                         chan = agent_new(p, AST_STATE_DOWN);
1333                         if (!chan) 
1334                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1335                 } else
1336                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1337         }
1338         *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1339         AST_LIST_UNLOCK(&agents);
1340         return chan;
1341 }
1342
1343 static force_inline int powerof(unsigned int d)
1344 {
1345         int x = ffs(d);
1346
1347         if (x)
1348                 return x - 1;
1349
1350         return 0;
1351 }
1352
1353 /*!
1354  * Lists agents and their status to the Manager API.
1355  * It is registered on load_module() and it gets called by the manager backend.
1356  * \param s
1357  * \param m
1358  * \returns 
1359  * \sa action_agent_logoff(), action_agent_callback_login(), load_module().
1360  */
1361 static int action_agents(struct mansession *s, struct message *m)
1362 {
1363         char *id = astman_get_header(m,"ActionID");
1364         char idText[256] = "";
1365         char chanbuf[256];
1366         struct agent_pvt *p;
1367         char *username = NULL;
1368         char *loginChan = NULL;
1369         char *talkingtoChan = NULL;
1370         char *status = NULL;
1371
1372         if (!ast_strlen_zero(id))
1373                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1374         astman_send_ack(s, m, "Agents will follow");
1375         AST_LIST_LOCK(&agents);
1376         AST_LIST_TRAVERSE(&agents, p, list) {
1377                 ast_mutex_lock(&p->lock);
1378
1379                 /* Status Values:
1380                    AGENT_LOGGEDOFF - Agent isn't logged in
1381                    AGENT_IDLE      - Agent is logged in, and waiting for call
1382                    AGENT_ONCALL    - Agent is logged in, and on a call
1383                    AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1384
1385                 username = S_OR(p->name, "None");
1386
1387                 /* Set a default status. It 'should' get changed. */
1388                 status = "AGENT_UNKNOWN";
1389
1390                 if (!ast_strlen_zero(p->loginchan) && !p->chan) {
1391                         loginChan = p->loginchan;
1392                         talkingtoChan = "n/a";
1393                         status = "AGENT_IDLE";
1394                         if (p->acknowledged) {
1395                                 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
1396                                 loginChan = chanbuf;
1397                         }
1398                 } else if (p->chan) {
1399                         loginChan = ast_strdupa(p->chan->name);
1400                         if (p->owner && p->owner->_bridge) {
1401                                 talkingtoChan = p->chan->cid.cid_num;
1402                                 status = "AGENT_ONCALL";
1403                         } else {
1404                                 talkingtoChan = "n/a";
1405                                 status = "AGENT_IDLE";
1406                         }
1407                 } else {
1408                         loginChan = "n/a";
1409                         talkingtoChan = "n/a";
1410                         status = "AGENT_LOGGEDOFF";
1411                 }
1412
1413                 astman_append(s, "Event: Agents\r\n"
1414                         "Agent: %s\r\n"
1415                         "Name: %s\r\n"
1416                         "Status: %s\r\n"
1417                         "LoggedInChan: %s\r\n"
1418                         "LoggedInTime: %d\r\n"
1419                         "TalkingTo: %s\r\n"
1420                         "%s"
1421                         "\r\n",
1422                         p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
1423                 ast_mutex_unlock(&p->lock);
1424         }
1425         AST_LIST_UNLOCK(&agents);
1426         astman_append(s, "Event: AgentsComplete\r\n"
1427                 "%s"
1428                 "\r\n",idText);
1429         return 0;
1430 }
1431
1432 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
1433 {
1434         char *tmp = NULL;
1435         char agent[AST_MAX_AGENT];
1436
1437         if (!ast_strlen_zero(logcommand))
1438                 tmp = logcommand;
1439         else
1440                 tmp = ast_strdupa("");
1441
1442         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1443
1444         if (!ast_strlen_zero(uniqueid)) {
1445                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1446                                 "Agent: %s\r\n"
1447                                 "Reason: %s\r\n"
1448                                 "Loginchan: %s\r\n"
1449                                 "Logintime: %ld\r\n"
1450                                 "Uniqueid: %s\r\n", 
1451                                 p->agent, tmp, loginchan, logintime, uniqueid);
1452         } else {
1453                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1454                                 "Agent: %s\r\n"
1455                                 "Reason: %s\r\n"
1456                                 "Loginchan: %s\r\n"
1457                                 "Logintime: %ld\r\n",
1458                                 p->agent, tmp, loginchan, logintime);
1459         }
1460
1461         ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
1462         set_agentbycallerid(p->logincallerid, NULL);
1463         p->loginchan[0] ='\0';
1464         p->logincallerid[0] = '\0';
1465         ast_device_state_changed("Agent/%s", p->agent);
1466         if (persistent_agents)
1467                 dump_agents();  
1468
1469 }
1470
1471 static int agent_logoff(char *agent, int soft)
1472 {
1473         struct agent_pvt *p;
1474         long logintime;
1475         int ret = -1; /* Return -1 if no agent if found */
1476
1477         AST_LIST_TRAVERSE(&agents, p, list) {
1478                 if (!strcasecmp(p->agent, agent)) {
1479                         if (!soft) {
1480                                 if (p->owner)
1481                                         ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1482                                 if (p->chan) 
1483                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1484                         }
1485                         ret = 0; /* found an agent => return 0 */
1486                         logintime = time(NULL) - p->loginstart;
1487                         p->loginstart = 0;
1488                         agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
1489                         break;
1490                 }
1491         }
1492
1493         return ret;
1494 }
1495
1496 static int agent_logoff_cmd(int fd, int argc, char **argv)
1497 {
1498         int ret;
1499         char *agent;
1500
1501         if (argc < 3 || argc > 4)
1502                 return RESULT_SHOWUSAGE;
1503         if (argc == 4 && strcasecmp(argv[3], "soft"))
1504                 return RESULT_SHOWUSAGE;
1505
1506         agent = argv[2] + 6;
1507         ret = agent_logoff(agent, argc == 4);
1508         if (ret == 0)
1509                 ast_cli(fd, "Logging out %s\n", agent);
1510
1511         return RESULT_SUCCESS;
1512 }
1513
1514 /*!
1515  * Sets an agent as no longer logged in in the Manager API.
1516  * It is registered on load_module() and it gets called by the manager backend.
1517  * \param s
1518  * \param m
1519  * \returns 
1520  * \sa action_agents(), action_agent_callback_login(), load_module().
1521  */
1522 static int action_agent_logoff(struct mansession *s, struct message *m)
1523 {
1524         char *agent = astman_get_header(m, "Agent");
1525         char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1526         int soft;
1527         int ret; /* return value of agent_logoff */
1528
1529         if (ast_strlen_zero(agent)) {
1530                 astman_send_error(s, m, "No agent specified");
1531                 return 0;
1532         }
1533
1534         soft = ast_true(soft_s) ? 1 : 0;
1535         ret = agent_logoff(agent, soft);
1536         if (ret == 0)
1537                 astman_send_ack(s, m, "Agent logged out");
1538         else
1539                 astman_send_error(s, m, "No such agent");
1540
1541         return 0;
1542 }
1543
1544 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1545 {
1546         if (pos == 2) {
1547                 struct agent_pvt *p;
1548                 char name[AST_MAX_AGENT];
1549                 int which = 0, len = strlen(word);
1550
1551                 AST_LIST_TRAVERSE(&agents, p, list) {
1552                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1553                         if (!strncasecmp(word, name, len) && ++which > state)
1554                                 return ast_strdup(name);
1555                 }
1556         } else if (pos == 3 && state == 0) 
1557                 return ast_strdup("soft");
1558         
1559         return NULL;
1560 }
1561
1562 /*!
1563  * Show agents in cli.
1564  */
1565 static int agents_show(int fd, int argc, char **argv)
1566 {
1567         struct agent_pvt *p;
1568         char username[AST_MAX_BUF];
1569         char location[AST_MAX_BUF] = "";
1570         char talkingto[AST_MAX_BUF] = "";
1571         char moh[AST_MAX_BUF];
1572         int count_agents = 0;           /*!< Number of agents configured */
1573         int online_agents = 0;          /*!< Number of online agents */
1574         int offline_agents = 0;         /*!< Number of offline agents */
1575         if (argc != 2)
1576                 return RESULT_SHOWUSAGE;
1577         AST_LIST_LOCK(&agents);
1578         AST_LIST_TRAVERSE(&agents, p, list) {
1579                 ast_mutex_lock(&p->lock);
1580                 if (p->pending) {
1581                         if (p->group)
1582                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1583                         else
1584                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1585                 } else {
1586                         if (!ast_strlen_zero(p->name))
1587                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1588                         else
1589                                 username[0] = '\0';
1590                         if (p->chan) {
1591                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1592                                 if (p->owner && ast_bridged_channel(p->owner))
1593                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1594                                  else 
1595                                         strcpy(talkingto, " is idle");
1596                                 online_agents++;
1597                         } else if (!ast_strlen_zero(p->loginchan)) {
1598                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
1599                                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1600                                 else 
1601                                         snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
1602                                 talkingto[0] = '\0';
1603                                 online_agents++;
1604                                 if (p->acknowledged)
1605                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1606                         } else {
1607                                 strcpy(location, "not logged in");
1608                                 talkingto[0] = '\0';
1609                                 offline_agents++;
1610                         }
1611                         if (!ast_strlen_zero(p->moh))
1612                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1613                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1614                                 username, location, talkingto, moh);
1615                         count_agents++;
1616                 }
1617                 ast_mutex_unlock(&p->lock);
1618         }
1619         AST_LIST_UNLOCK(&agents);
1620         if ( !count_agents ) 
1621                 ast_cli(fd, "No Agents are configured in %s\n",config);
1622         else 
1623                 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1624         ast_cli(fd, "\n");
1625                         
1626         return RESULT_SUCCESS;
1627 }
1628
1629
1630 static int agents_show_online(int fd, int argc, char **argv)
1631 {
1632         struct agent_pvt *p;
1633         char username[AST_MAX_BUF];
1634         char location[AST_MAX_BUF] = "";
1635         char talkingto[AST_MAX_BUF] = "";
1636         char moh[AST_MAX_BUF];
1637         int count_agents = 0;           /* Number of agents configured */
1638         int online_agents = 0;          /* Number of online agents */
1639         int agent_status = 0;           /* 0 means offline, 1 means online */
1640         if (argc != 3)
1641                 return RESULT_SHOWUSAGE;
1642         AST_LIST_LOCK(&agents);
1643         AST_LIST_TRAVERSE(&agents, p, list) {
1644                 agent_status = 0;       /* reset it to offline */
1645                 ast_mutex_lock(&p->lock);
1646                 if (!ast_strlen_zero(p->name))
1647                         snprintf(username, sizeof(username), "(%s) ", p->name);
1648                 else
1649                         username[0] = '\0';
1650                 if (p->chan) {
1651                         snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1652                         if (p->owner && ast_bridged_channel(p->owner)) 
1653                                 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1654                         else 
1655                                 strcpy(talkingto, " is idle");
1656                         agent_status = 1;
1657                         online_agents++;
1658                 } else if (!ast_strlen_zero(p->loginchan)) {
1659                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1660                         talkingto[0] = '\0';
1661                         agent_status = 1;
1662                         online_agents++;
1663                         if (p->acknowledged)
1664                                 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1665                 }
1666                 if (!ast_strlen_zero(p->moh))
1667                         snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1668                 if (agent_status)
1669                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
1670                 count_agents++;
1671                 ast_mutex_unlock(&p->lock);
1672         }
1673         AST_LIST_UNLOCK(&agents);
1674         if (!count_agents) 
1675                 ast_cli(fd, "No Agents are configured in %s\n", config);
1676         else
1677                 ast_cli(fd, "%d agents online\n", online_agents);
1678         ast_cli(fd, "\n");
1679         return RESULT_SUCCESS;
1680 }
1681
1682
1683
1684 static char show_agents_usage[] = 
1685 "Usage: agent list\n"
1686 "       Provides summary information on agents.\n";
1687
1688 static char show_agents_online_usage[] =
1689 "Usage: agent list online\n"
1690 "       Provides a list of all online agents.\n";
1691
1692 static char agent_logoff_usage[] =
1693 "Usage: agent logoff <channel> [soft]\n"
1694 "       Sets an agent as no longer logged in.\n"
1695 "       If 'soft' is specified, do not hangup existing calls.\n";
1696
1697 static struct ast_cli_entry cli_show_agents_deprecated = {
1698         { "show", "agents", NULL },
1699         agents_show, NULL,
1700         NULL, NULL };
1701
1702 static struct ast_cli_entry cli_show_agents_online_deprecated = {
1703         { "show", "agents", "online" },
1704         agents_show_online, NULL,
1705         NULL, NULL };
1706
1707 static struct ast_cli_entry cli_agents[] = {
1708         { { "agent", "list", NULL },
1709         agents_show, "Show status of agents",
1710         show_agents_usage, NULL, &cli_show_agents_deprecated },
1711
1712         { { "agent", "list", "online" },
1713         agents_show_online, "Show all online agents",
1714         show_agents_online_usage, NULL, &cli_show_agents_online_deprecated },
1715
1716         { { "agent", "logoff", NULL },
1717         agent_logoff_cmd, "Sets an agent offline",
1718         agent_logoff_usage, complete_agent_logoff_cmd },
1719 };
1720
1721 /*!
1722  * \brief Log in agent application.
1723  *
1724  * \param chan
1725  * \param data
1726  * \param callbackmode non-zero for AgentCallbackLogin
1727  */
1728 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1729 {
1730         int res=0;
1731         int tries = 0;
1732         int max_login_tries = maxlogintries;
1733         struct agent_pvt *p;
1734         struct ast_module_user *u;
1735         int login_state = 0;
1736         char user[AST_MAX_AGENT] = "";
1737         char pass[AST_MAX_AGENT];
1738         char agent[AST_MAX_AGENT] = "";
1739         char xpass[AST_MAX_AGENT] = "";
1740         char *errmsg;
1741         char *parse;
1742         AST_DECLARE_APP_ARGS(args,
1743                              AST_APP_ARG(agent_id);
1744                              AST_APP_ARG(options);
1745                              AST_APP_ARG(extension);
1746                 );
1747         const char *tmpoptions = NULL;
1748         char *context = NULL;
1749         int play_announcement = 1;
1750         char agent_goodbye[AST_MAX_FILENAME_LEN];
1751         int update_cdr = updatecdr;
1752         char *filename = "agent-loginok";
1753         char tmpchan[AST_MAX_BUF] = "";
1754
1755         u = ast_module_user_add(chan);
1756
1757         parse = ast_strdupa(data);
1758
1759         AST_STANDARD_APP_ARGS(args, parse);
1760
1761         ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1762
1763         /* Set Channel Specific Login Overrides */
1764         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1765                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1766                 if (max_login_tries < 0)
1767                         max_login_tries = 0;
1768                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1769                 if (option_verbose > 2)
1770                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1771         }
1772         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1773                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1774                         update_cdr = 1;
1775                 else
1776                         update_cdr = 0;
1777                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1778                 if (option_verbose > 2)
1779                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1780         }
1781         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1782                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1783                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1784                 if (option_verbose > 2)
1785                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1786         }
1787         /* End Channel Specific Login Overrides */
1788         
1789         if (callbackmode && args.extension) {
1790                 parse = args.extension;
1791                 args.extension = strsep(&parse, "@");
1792                 context = parse;
1793         }
1794
1795         if (!ast_strlen_zero(args.options)) {
1796                 if (strchr(args.options, 's')) {
1797                         play_announcement = 0;
1798                 }
1799         }
1800
1801         if (chan->_state != AST_STATE_UP)
1802                 res = ast_answer(chan);
1803         if (!res) {
1804                 if (!ast_strlen_zero(args.agent_id))
1805                         ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1806                 else
1807                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1808         }
1809         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1810                 tries++;
1811                 /* Check for password */
1812                 AST_LIST_LOCK(&agents);
1813                 AST_LIST_TRAVERSE(&agents, p, list) {
1814                         if (!strcmp(p->agent, user) && !p->pending)
1815                                 ast_copy_string(xpass, p->password, sizeof(xpass));
1816                 }
1817                 AST_LIST_UNLOCK(&agents);
1818                 if (!res) {
1819                         if (!ast_strlen_zero(xpass))
1820                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1821                         else
1822                                 pass[0] = '\0';
1823                 }
1824                 errmsg = "agent-incorrect";
1825
1826 #if 0
1827                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1828 #endif          
1829
1830                 /* Check again for accuracy */
1831                 AST_LIST_LOCK(&agents);
1832                 AST_LIST_TRAVERSE(&agents, p, list) {
1833                         ast_mutex_lock(&p->lock);
1834                         if (!strcmp(p->agent, user) &&
1835                             !strcmp(p->password, pass) && !p->pending) {
1836                                 login_state = 1; /* Successful Login */
1837
1838                                 /* Ensure we can't be gotten until we're done */
1839                                 gettimeofday(&p->lastdisc, NULL);
1840                                 p->lastdisc.tv_sec++;
1841
1842                                 /* Set Channel Specific Agent Overrides */
1843                                 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1844                                         if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1845                                                 p->ackcall = 2;
1846                                         else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1847                                                 p->ackcall = 1;
1848                                         else
1849                                                 p->ackcall = 0;
1850                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1851                                         if (option_verbose > 2)
1852                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1853                                 }
1854                                 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1855                                         p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1856                                         if (p->autologoff < 0)
1857                                                 p->autologoff = 0;
1858                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1859                                         if (option_verbose > 2)
1860                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1861                                 }
1862                                 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1863                                         p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1864                                         if (p->wrapuptime < 0)
1865                                                 p->wrapuptime = 0;
1866                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1867                                         if (option_verbose > 2)
1868                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1869                                 }
1870                                 /* End Channel Specific Agent Overrides */
1871                                 if (!p->chan) {
1872                                         char last_loginchan[80] = "";
1873                                         long logintime;
1874                                         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1875
1876                                         if (callbackmode) {
1877                                                 int pos = 0;
1878                                                 /* Retrieve login chan */
1879                                                 for (;;) {
1880                                                         if (!ast_strlen_zero(args.extension)) {
1881                                                                 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
1882                                                                 res = 0;
1883                                                         } else
1884                                                                 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1885                                                         if (ast_strlen_zero(tmpchan) )
1886                                                                 break;
1887                                                         if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) {
1888                                                                 if(!allow_multiple_login(tmpchan,context) ) {
1889                                                                         args.extension = NULL;
1890                                                                         pos = 0;
1891                                                                 } else
1892                                                                         break;
1893                                                         }
1894                                                         if (args.extension) {
1895                                                                 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
1896                                                                 args.extension = NULL;
1897                                                                 pos = 0;
1898                                                         } else {
1899                                                                 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent);
1900                                                                 res = ast_streamfile(chan, "invalid", chan->language);
1901                                                                 if (!res)
1902                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
1903                                                                 if (res > 0) {
1904                                                                         tmpchan[0] = res;
1905                                                                         tmpchan[1] = '\0';
1906                                                                         pos = 1;
1907                                                                 } else {
1908                                                                         tmpchan[0] = '\0';
1909                                                                         pos = 0;
1910                                                                 }
1911                                                         }
1912                                                 }
1913                                                 args.extension = tmpchan;
1914                                                 if (!res) {
1915                                                         set_agentbycallerid(p->logincallerid, NULL);
1916                                                         if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1917                                                                 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1918                                                         else {
1919                                                                 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1920                                                                 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1921                                                         }
1922                                                         p->acknowledged = 0;
1923                                                         if (ast_strlen_zero(p->loginchan)) {
1924                                                                 login_state = 2;
1925                                                                 filename = "agent-loggedoff";
1926                                                         } else {
1927                                                                 if (chan->cid.cid_num) {
1928                                                                         ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1929                                                                         set_agentbycallerid(p->logincallerid, p->agent);
1930                                                                 } else
1931                                                                         p->logincallerid[0] = '\0';
1932                                                         }
1933
1934                                                         if(update_cdr && chan->cdr)
1935                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1936
1937                                                 }
1938                                         } else {
1939                                                 p->loginchan[0] = '\0';
1940                                                 p->logincallerid[0] = '\0';
1941                                                 p->acknowledged = 0;
1942                                         }
1943                                         ast_mutex_unlock(&p->lock);
1944                                         AST_LIST_UNLOCK(&agents);
1945                                         if( !res && play_announcement==1 )
1946                                                 res = ast_streamfile(chan, filename, chan->language);
1947                                         if (!res)
1948                                                 ast_waitstream(chan, "");
1949                                         AST_LIST_LOCK(&agents);
1950                                         ast_mutex_lock(&p->lock);
1951                                         if (!res) {
1952                                                 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1953                                                 if (res)
1954                                                         ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1955                                         }
1956                                         if (!res) {
1957                                                 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1958                                                 if (res)
1959                                                         ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1960                                         }
1961                                         /* Check once more just in case */
1962                                         if (p->chan)
1963                                                 res = -1;
1964                                         if (callbackmode && !res) {
1965                                                 /* Just say goodbye and be done with it */
1966                                                 if (!ast_strlen_zero(p->loginchan)) {
1967                                                         if (p->loginstart == 0)
1968                                                                 time(&p->loginstart);
1969                                                         manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1970                                                                       "Agent: %s\r\n"
1971                                                                       "Loginchan: %s\r\n"
1972                                                                       "Uniqueid: %s\r\n",
1973                                                                       p->agent, p->loginchan, chan->uniqueid);
1974                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1975                                                         if (option_verbose > 1)
1976                                                                 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1977                                                         ast_device_state_changed("Agent/%s", p->agent);
1978                                                         if (persistent_agents)
1979                                                                 dump_agents();
1980                                                 } else {
1981                                                         logintime = time(NULL) - p->loginstart;
1982                                                         p->loginstart = 0;
1983
1984                                                         agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
1985                                                         if (option_verbose > 1)
1986                                                                 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1987                                                 }
1988                                                 AST_LIST_UNLOCK(&agents);
1989                                                 if (!res)
1990                                                         res = ast_safe_sleep(chan, 500);
1991                                                 ast_mutex_unlock(&p->lock);
1992                                         } else if (!res) {
1993                                                 ast_indicate_data(chan, AST_CONTROL_HOLD, 
1994                                                         S_OR(p->moh, NULL), 
1995                                                         !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
1996                                                 if (p->loginstart == 0)
1997                                                         time(&p->loginstart);
1998                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1999                                                               "Agent: %s\r\n"
2000                                                               "Channel: %s\r\n"
2001                                                               "Uniqueid: %s\r\n",
2002                                                               p->agent, chan->name, chan->uniqueid);
2003                                                 if (update_cdr && chan->cdr)
2004                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2005                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
2006                                                 if (option_verbose > 1)
2007                                                         ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
2008                                                                     ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
2009                                                 /* Login this channel and wait for it to go away */
2010                                                 p->chan = chan;
2011                                                 if (p->ackcall > 1)
2012                                                         check_beep(p, 0);
2013                                                 else
2014                                                         check_availability(p, 0);
2015                                                 ast_mutex_unlock(&p->lock);
2016                                                 AST_LIST_UNLOCK(&agents);
2017                                                 ast_device_state_changed("Agent/%s", p->agent);
2018                                                 while (res >= 0) {
2019                                                         ast_mutex_lock(&p->lock);
2020                                                         if (p->chan != chan)
2021                                                                 res = -1;
2022                                                         ast_mutex_unlock(&p->lock);
2023                                                         /* Yield here so other interested threads can kick in. */
2024                                                         sched_yield();
2025                                                         if (res)
2026                                                                 break;
2027
2028                                                         AST_LIST_LOCK(&agents);
2029                                                         ast_mutex_lock(&p->lock);
2030                                                         if (p->lastdisc.tv_sec) {
2031                                                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
2032                                                                         if (option_debug)
2033                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
2034                                                                         p->lastdisc = ast_tv(0, 0);
2035                                                                         if (p->ackcall > 1)
2036                                                                                 check_beep(p, 0);
2037                                                                         else
2038                                                                                 check_availability(p, 0);
2039                                                                 }
2040                                                         }
2041                                                         ast_mutex_unlock(&p->lock);
2042                                                         AST_LIST_UNLOCK(&agents);
2043                                                         /*      Synchronize channel ownership between call to agent and itself. */
2044                                                         ast_mutex_lock( &p->app_lock );
2045                                                         ast_mutex_lock(&p->lock);
2046                                                         p->owning_app = pthread_self();
2047                                                         ast_mutex_unlock(&p->lock);
2048                                                         if (p->ackcall > 1) 
2049                                                                 res = agent_ack_sleep(p);
2050                                                         else
2051                                                                 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2052                                                         ast_mutex_unlock( &p->app_lock );
2053                                                         if ((p->ackcall > 1)  && (res == 1)) {
2054                                                                 AST_LIST_LOCK(&agents);
2055                                                                 ast_mutex_lock(&p->lock);
2056                                                                 check_availability(p, 0);
2057                                                                 ast_mutex_unlock(&p->lock);
2058                                                                 AST_LIST_UNLOCK(&agents);
2059                                                                 res = 0;
2060                                                         }
2061                                                         sched_yield();
2062                                                 }
2063                                                 ast_mutex_lock(&p->lock);
2064                                                 if (res && p->owner) 
2065                                                         ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
2066                                                 /* Log us off if appropriate */
2067                                                 if (p->chan == chan)
2068                                                         p->chan = NULL;
2069                                                 p->acknowledged = 0;
2070                                                 logintime = time(NULL) - p->loginstart;
2071                                                 p->loginstart = 0;
2072                                                 ast_mutex_unlock(&p->lock);
2073                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2074                                                               "Agent: %s\r\n"
2075                                                               "Logintime: %ld\r\n"
2076                                                               "Uniqueid: %s\r\n",
2077                                                               p->agent, logintime, chan->uniqueid);
2078                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2079                                                 if (option_verbose > 1)
2080                                                         ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
2081                                                 /* If there is no owner, go ahead and kill it now */
2082                                                 ast_device_state_changed("Agent/%s", p->agent);
2083                                                 if (p->dead && !p->owner) {
2084                                                         ast_mutex_destroy(&p->lock);
2085                                                         ast_mutex_destroy(&p->app_lock);
2086                                                         free(p);
2087                                                 }
2088                                         }
2089                                         else {
2090                                                 ast_mutex_unlock(&p->lock);
2091                                                 p = NULL;
2092                                         }
2093                                         res = -1;
2094                                 } else {
2095                                         ast_mutex_unlock(&p->lock);
2096                                         errmsg = "agent-alreadyon";
2097                                         p = NULL;
2098                                 }
2099                                 break;
2100                         }
2101                         ast_mutex_unlock(&p->lock);
2102                 }
2103                 if (!p)
2104                         AST_LIST_UNLOCK(&agents);
2105
2106                 if (!res && (max_login_tries==0 || tries < max_login_tries))
2107                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2108         }
2109                 
2110         if (!res)
2111                 res = ast_safe_sleep(chan, 500);
2112
2113         /* AgentLogin() exit */
2114         if (!callbackmode) {
2115                 ast_module_user_remove(u);
2116                 return -1;
2117         } else { /* AgentCallbackLogin() exit*/
2118                 /* Set variables */
2119                 if (login_state > 0) {
2120                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
2121                         if (login_state==1) {
2122                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
2123                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
2124                         } else 
2125                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
2126                 } else {
2127                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
2128                 }
2129                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
2130                         ast_module_user_remove(u);
2131                         return 0;
2132                 }
2133                 /* Do we need to play agent-goodbye now that we will be hanging up? */
2134                 if (play_announcement) {
2135                         if (!res)
2136                                 res = ast_safe_sleep(chan, 1000);
2137                         res = ast_streamfile(chan, agent_goodbye, chan->language);
2138                         if (!res)
2139                                 res = ast_waitstream(chan, "");
2140                         if (!res)
2141                                 res = ast_safe_sleep(chan, 1000);
2142                 }
2143         }
2144
2145         ast_module_user_remove(u);
2146         
2147         /* We should never get here if next priority exists when in callbackmode */
2148         return -1;
2149 }
2150
2151 /*!
2152  * Called by the AgentLogin application (from the dial plan).
2153  * 
2154  * \param chan
2155  * \param data
2156  * \returns
2157  * \sa callback_login_exec(), agentmonitoroutgoing_exec(), load_module().
2158  */
2159 static int login_exec(struct ast_channel *chan, void *data)
2160 {
2161         return __login_exec(chan, data, 0);
2162 }
2163
2164 static void callback_deprecated(void)
2165 {
2166         static int depwarning = 0;
2167
2168         if (!depwarning) {
2169                 depwarning = 1;
2170
2171                 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
2172                 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
2173                 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
2174         }
2175 }
2176
2177 /*!
2178  *  Called by the AgentCallbackLogin application (from the dial plan).
2179  * 
2180  * \param chan
2181  * \param data
2182  * \returns
2183  * \sa login_exec(), agentmonitoroutgoing_exec(), load_module().
2184  */
2185 static int callback_exec(struct ast_channel *chan, void *data)
2186 {
2187         callback_deprecated();
2188
2189         return __login_exec(chan, data, 1);
2190 }
2191
2192 /*!
2193  * Sets an agent as logged in by callback in the Manager API.
2194  * It is registered on load_module() and it gets called by the manager backend.
2195  * \param s
2196  * \param m
2197  * \returns 
2198  * \sa action_agents(), action_agent_logoff(), load_module().
2199  */
2200 static int action_agent_callback_login(struct mansession *s, struct message *m)
2201 {
2202         char *agent = astman_get_header(m, "Agent");
2203         char *exten = astman_get_header(m, "Exten");
2204         char *context = astman_get_header(m, "Context");
2205         char *wrapuptime_s = astman_get_header(m, "WrapupTime");
2206         char *ackcall_s = astman_get_header(m, "AckCall");
2207         struct agent_pvt *p;
2208         int login_state = 0;
2209
2210         callback_deprecated();
2211
2212         if (ast_strlen_zero(agent)) {
2213                 astman_send_error(s, m, "No agent specified");
2214                 return 0;
2215         }
2216
2217         if (ast_strlen_zero(exten)) {
2218                 astman_send_error(s, m, "No extension specified");
2219                 return 0;
2220         }
2221
2222         AST_LIST_LOCK(&agents);
2223         AST_LIST_TRAVERSE(&agents, p, list) {
2224                 if (strcmp(p->agent, agent) || p->pending) 
2225                         continue;
2226                 if (p->chan) {
2227                         login_state = 2; /* already logged in (and on the phone)*/
2228                         break;
2229                 }
2230                 ast_mutex_lock(&p->lock);
2231                 login_state = 1; /* Successful Login */
2232                 
2233                 if (ast_strlen_zero(context))
2234                         ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
2235                 else
2236                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
2237
2238                 if (!ast_strlen_zero(wrapuptime_s)) {
2239                         p->wrapuptime = atoi(wrapuptime_s);
2240                         if (p->wrapuptime < 0)
2241                                 p->wrapuptime = 0;
2242                 }
2243
2244                 if (ast_true(ackcall_s))
2245                         p->ackcall = 1;
2246                 else
2247                         p->ackcall = 0;
2248
2249                 if (p->loginstart == 0)
2250                         time(&p->loginstart);
2251                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
2252                               "Agent: %s\r\n"
2253                               "Loginchan: %s\r\n",
2254                               p->agent, p->loginchan);
2255                 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
2256                 if (option_verbose > 1)
2257                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
2258                 ast_device_state_changed("Agent/%s", p->agent);
2259                 ast_mutex_unlock(&p->lock);
2260                 if (persistent_agents)
2261                         dump_agents();
2262         }
2263         AST_LIST_UNLOCK(&agents);
2264
2265         if (login_state == 1)
2266                 astman_send_ack(s, m, "Agent logged in");
2267         else if (login_state == 0)
2268                 astman_send_error(s, m, "No such agent");
2269         else if (login_state == 2)
2270                 astman_send_error(s, m, "Agent already logged in");
2271
2272         return 0;
2273 }
2274
2275 /*!
2276  *  \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2277  *
2278  * \param chan
2279  * \param data
2280  * \returns
2281  * \sa login_exec(), callback_login_exec(), load_module().
2282  */
2283 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2284 {
2285         int exitifnoagentid = 0;
2286         int nowarnings = 0;
2287         int changeoutgoing = 0;
2288         int res = 0;
2289         char agent[AST_MAX_AGENT];
2290
2291         if (data) {
2292                 if (strchr(data, 'd'))
2293                         exitifnoagentid = 1;
2294                 if (strchr(data, 'n'))
2295                         nowarnings = 1;
2296                 if (strchr(data, 'c'))
2297                         changeoutgoing = 1;
2298         }
2299         if (chan->cid.cid_num) {
2300                 const char *tmp;
2301                 char agentvar[AST_MAX_BUF];
2302                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2303                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2304                         struct agent_pvt *p;
2305                         ast_copy_string(agent, tmp, sizeof(agent));
2306                         AST_LIST_LOCK(&agents);
2307                         AST_LIST_TRAVERSE(&agents, p, list) {
2308                                 if (!strcasecmp(p->agent, tmp)) {
2309                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2310                                         __agent_start_monitoring(chan, p, 1);
2311                                         break;
2312                                 }
2313                         }
2314                         AST_LIST_UNLOCK(&agents);
2315                         
2316                 } else {
2317                         res = -1;
2318                         if (!nowarnings)
2319                                 ast_log(LOG_WARNING, "Couldn't find the global variable %s, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n", agentvar);
2320                 }
2321         } else {
2322                 res = -1;
2323                 if (!nowarnings)
2324                         ast_log(LOG_WARNING, "There is no callerid on that call, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n");
2325         }
2326         /* check if there is n + 101 priority */
2327         /*! \todo XXX Needs to check option priorityjump etc etc */
2328         if (res) {
2329                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2330                         chan->priority+=100;
2331                         if (option_verbose > 2)
2332                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2333                 } else if (exitifnoagentid)
2334                         return res;
2335         }
2336         return 0;
2337 }
2338
2339 /*!
2340  * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
2341  */
2342 static void dump_agents(void)
2343 {
2344         struct agent_pvt *cur_agent = NULL;
2345         char buf[256];
2346
2347         AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2348                 if (cur_agent->chan)
2349                         continue;
2350
2351                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2352                         snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2353                         if (ast_db_put(pa_family, cur_agent->agent, buf))
2354                                 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
2355                         else if (option_debug)
2356                                 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2357                 } else {
2358                         /* Delete -  no agent or there is an error */
2359                         ast_db_del(pa_family, cur_agent->agent);
2360                 }
2361         }
2362 }
2363
2364 /*!
2365  * \brief Reload the persistent agents from astdb.
2366  */
2367 static void reload_agents(void)
2368 {
2369         char *agent_num;
2370         struct ast_db_entry *db_tree;
2371         struct ast_db_entry *entry;
2372         struct agent_pvt *cur_agent;
2373         char agent_data[256];
2374         char *parse;
2375         char *agent_chan;
2376         char *agent_callerid;
2377
2378         db_tree = ast_db_gettree(pa_family, NULL);
2379
2380         AST_LIST_LOCK(&agents);
2381         for (entry = db_tree; entry; entry = entry->next) {
2382                 agent_num = entry->key + strlen(pa_family) + 2;
2383                 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2384                         ast_mutex_lock(&cur_agent->lock);
2385                         if (strcmp(agent_num, cur_agent->agent) == 0)
2386                                 break;
2387                         ast_mutex_unlock(&cur_agent->lock);
2388                 }
2389                 if (!cur_agent) {
2390                         ast_db_del(pa_family, agent_num);
2391                         continue;
2392                 } else
2393                         ast_mutex_unlock(&cur_agent->lock);
2394                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2395                         if (option_debug)
2396                                 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
2397                         parse = agent_data;
2398                         agent_chan = strsep(&parse, ";");
2399                         agent_callerid = strsep(&parse, ";");
2400                         ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2401                         if (agent_callerid) {
2402                                 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2403                                 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2404                         } else
2405                                 cur_agent->logincallerid[0] = '\0';
2406                         if (cur_agent->loginstart == 0)
2407                                 time(&cur_agent->loginstart);
2408                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2409                 }
2410         }
2411         AST_LIST_UNLOCK(&agents);
2412         if (db_tree) {
2413                 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
2414                 ast_db_freetree(db_tree);
2415         }
2416 }
2417
2418 /*! \brief Part of PBX channel interface */
2419 static int agent_devicestate(void *data)
2420 {
2421         struct agent_pvt *p;
2422         char *s;
2423         ast_group_t groupmatch;
2424         int groupoff;
2425         int waitforagent=0;
2426         int res = AST_DEVICE_INVALID;
2427         
2428         s = data;
2429         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
2430                 groupmatch = (1 << groupoff);
2431         else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2432                 groupmatch = (1 << groupoff);
2433                 waitforagent = 1;
2434         } else 
2435                 groupmatch = 0;
2436
2437         /* Check actual logged in agents first */
2438         AST_LIST_LOCK(&agents);
2439         AST_LIST_TRAVERSE(&agents, p, list) {
2440                 ast_mutex_lock(&p->lock);
2441                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2442                         if (p->owner) {
2443                                 if (res != AST_DEVICE_INUSE)
2444                                         res = AST_DEVICE_BUSY;
2445                         } else {
2446                                 if (res == AST_DEVICE_BUSY)
2447                                         res = AST_DEVICE_INUSE;
2448                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2449                                         if (res == AST_DEVICE_INVALID)
2450                                                 res = AST_DEVICE_UNKNOWN;
2451                                 } else if (res == AST_DEVICE_INVALID)   
2452                                         res = AST_DEVICE_UNAVAILABLE;
2453                         }
2454                         if (!strcmp(data, p->agent)) {
2455                                 ast_mutex_unlock(&p->lock);
2456                                 break;
2457                         }
2458                 }
2459                 ast_mutex_unlock(&p->lock);
2460         }
2461         AST_LIST_UNLOCK(&agents);
2462         return res;
2463 }
2464
2465 static struct agent_pvt *find_agent(char *agentid)
2466 {
2467         struct agent_pvt *cur;
2468
2469         AST_LIST_TRAVERSE(&agents, cur, list) {
2470                 if (!strcmp(cur->agent, agentid))
2471                         break;  
2472         }
2473
2474         return cur;     
2475 }
2476
2477 static int function_agent(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
2478 {
2479         char *parse;    
2480         AST_DECLARE_APP_ARGS(args,
2481                 AST_APP_ARG(agentid);
2482                 AST_APP_ARG(item);
2483         );
2484         char *tmp;
2485         struct agent_pvt *agent;
2486
2487         buf[0] = '\0';
2488
2489         if (ast_strlen_zero(data)) {
2490                 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2491                 return -1;
2492         }
2493
2494         parse = ast_strdupa(data);
2495
2496         AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2497         if (!args.item)
2498                 args.item = "status";
2499
2500         if (!(agent = find_agent(args.agentid))) {
2501                 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2502                 return -1;
2503         }
2504
2505         if (!strcasecmp(args.item, "status")) {
2506                 char *status = "LOGGEDOUT";
2507                 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
2508                         status = "LOGGEDIN";    
2509                 ast_copy_string(buf, status, len);
2510         } else if (!strcasecmp(args.item, "password")) 
2511                 ast_copy_string(buf, agent->password, len);
2512         else if (!strcasecmp(args.item, "name"))
2513                 ast_copy_string(buf, agent->name, len);
2514         else if (!strcasecmp(args.item, "mohclass"))
2515                 ast_copy_string(buf, agent->moh, len);
2516         else if (!strcasecmp(args.item, "channel")) {
2517                 if (agent->chan) {
2518                         ast_copy_string(buf, agent->chan->name, len);
2519                         tmp = strrchr(buf, '-');
2520                         if (tmp)
2521                                 *tmp = '\0';
2522                 } 
2523         } else if (!strcasecmp(args.item, "exten"))
2524                 ast_copy_string(buf, agent->loginchan, len);    
2525
2526         return 0;
2527 }
2528
2529 struct ast_custom_function agent_function = {
2530         .name = "AGENT",
2531         .synopsis = "Gets information about an Agent",
2532         .syntax = "AGENT(<agentid>[:item])",
2533         .read = function_agent,
2534         .desc = "The valid items to retrieve are:\n"
2535         "- status (default)      The status of the agent\n"
2536         "                          LOGGEDIN | LOGGEDOUT\n"
2537         "- password              The password of the agent\n"
2538         "- name                  The name of the agent\n"
2539         "- mohclass              MusicOnHold class\n"
2540         "- exten                 The callback extension for the Agent (AgentCallbackLogin)\n"
2541         "- channel               The name of the active channel for the Agent (AgentLogin)\n"
2542 };
2543
2544
2545 /*!
2546  * \brief Initialize the Agents module.
2547  * This function is being called by Asterisk when loading the module. 
2548  * Among other things it registers applications, cli commands and reads the cofiguration file.
2549  *
2550  * \returns int Always 0.
2551  */
2552 static int load_module(void)
2553 {
2554         /* Make sure we can register our agent channel type */
2555         if (ast_channel_register(&agent_tech)) {
2556                 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2557                 return -1;
2558         }
2559         /* Read in the config */
2560         if (!read_agent_config())
2561                 return AST_MODULE_LOAD_DECLINE;
2562         if (persistent_agents)
2563                 reload_agents();
2564         /* Dialplan applications */
2565         ast_register_application(app, login_exec, synopsis, descrip);
2566         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2567         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2568
2569         /* Manager commands */
2570         ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2571         ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2572         ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
2573
2574         /* CLI Commands */
2575         ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2576
2577         /* Dialplan Functions */
2578         ast_custom_function_register(&agent_function);
2579
2580         return 0;
2581 }
2582
2583 static int reload(void)
2584 {
2585         read_agent_config();
2586         if (persistent_agents)
2587                 reload_agents();
2588         return 0;
2589 }
2590
2591 static int unload_module(void)
2592 {
2593         struct agent_pvt *p;
2594         /* First, take us out of the channel loop */
2595         ast_channel_unregister(&agent_tech);
2596         /* Unregister dialplan functions */
2597         ast_custom_function_unregister(&agent_function);        
2598         /* Unregister CLI commands */
2599         ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2600         /* Unregister dialplan applications */
2601         ast_unregister_application(app);
2602         ast_unregister_application(app2);
2603         ast_unregister_application(app3);
2604         /* Unregister manager command */
2605         ast_manager_unregister("Agents");
2606         ast_manager_unregister("AgentLogoff");
2607         ast_manager_unregister("AgentCallbackLogin");
2608         /* Unregister channel */
2609         AST_LIST_LOCK(&agents);
2610         /* Hangup all interfaces if they have an owner */
2611         while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2612                 if (p->owner)
2613                         ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2614                 free(p);
2615         }
2616         AST_LIST_UNLOCK(&agents);
2617         AST_LIST_HEAD_DESTROY(&agents);
2618         return 0;
2619 }
2620
2621 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
2622                 .load = load_module,
2623                 .unload = unload_module,
2624                 .reload = reload,
2625                );