Merged revisions 42133 via svnmerge from
[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                 if (ast_strlen_zero(p->loginchan))
819                         ast_mutex_unlock(&p->app_lock);
820         }
821         return 0;
822 }
823
824 static int agent_cont_sleep( void *data )
825 {
826         struct agent_pvt *p;
827         int res;
828
829         p = (struct agent_pvt *)data;
830
831         ast_mutex_lock(&p->lock);
832         res = p->app_sleep_cond;
833         if (p->lastdisc.tv_sec) {
834                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 
835                         res = 1;
836         }
837         ast_mutex_unlock(&p->lock);
838
839         if(option_debug > 4 && !res )
840                 ast_log(LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
841
842         return res;
843 }
844
845 static int agent_ack_sleep(void *data)
846 {
847         struct agent_pvt *p;
848         int res=0;
849         int to = 1000;
850         struct ast_frame *f;
851
852         /* Wait a second and look for something */
853
854         p = (struct agent_pvt *) data;
855         if (!p->chan) 
856                 return -1;
857
858         for(;;) {
859                 to = ast_waitfor(p->chan, to);
860                 if (to < 0) 
861                         return -1;
862                 if (!to) 
863                         return 0;
864                 f = ast_read(p->chan);
865                 if (!f) 
866                         return -1;
867                 if (f->frametype == AST_FRAME_DTMF)
868                         res = f->subclass;
869                 else
870                         res = 0;
871                 ast_frfree(f);
872                 ast_mutex_lock(&p->lock);
873                 if (!p->app_sleep_cond) {
874                         ast_mutex_unlock(&p->lock);
875                         return 0;
876                 } else if (res == '#') {
877                         ast_mutex_unlock(&p->lock);
878                         return 1;
879                 }
880                 ast_mutex_unlock(&p->lock);
881                 res = 0;
882         }
883         return res;
884 }
885
886 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
887 {
888         struct agent_pvt *p = bridge->tech_pvt;
889         struct ast_channel *ret = NULL;
890
891         if (p) {
892                 if (chan == p->chan)
893                         ret = bridge->_bridge;
894                 else if (chan == bridge->_bridge)
895                         ret = p->chan;
896         }
897
898         if (option_debug)
899                 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
900         return ret;
901 }
902
903 /*! \brief Create new agent channel */
904 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
905 {
906         struct ast_channel *tmp;
907 #if 0
908         if (!p->chan) {
909                 ast_log(LOG_WARNING, "No channel? :(\n");
910                 return NULL;
911         }
912 #endif  
913         tmp = ast_channel_alloc(0);
914         if (!tmp) {
915                 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
916                 return NULL;
917         }
918
919         tmp->tech = &agent_tech;
920         if (p->chan) {
921                 tmp->nativeformats = p->chan->nativeformats;
922                 tmp->writeformat = p->chan->writeformat;
923                 tmp->rawwriteformat = p->chan->writeformat;
924                 tmp->readformat = p->chan->readformat;
925                 tmp->rawreadformat = p->chan->readformat;
926                 ast_string_field_set(tmp, language, p->chan->language);
927                 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
928                 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
929                 /* XXX Is this really all we copy form the originating channel?? */
930         } else {
931                 tmp->nativeformats = AST_FORMAT_SLINEAR;
932                 tmp->writeformat = AST_FORMAT_SLINEAR;
933                 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
934                 tmp->readformat = AST_FORMAT_SLINEAR;
935                 tmp->rawreadformat = AST_FORMAT_SLINEAR;
936         }
937         if (p->pending)
938                 ast_string_field_build(tmp, name, "Agent/P%s-%d", p->agent, ast_random() & 0xffff);
939         else
940                 ast_string_field_build(tmp, name, "Agent/%s", p->agent);
941         /* Safe, agentlock already held */
942         ast_setstate(tmp, state);
943         tmp->tech_pvt = p;
944         p->owner = tmp;
945         /* XXX: this needs fixing */
946 #if 0
947         ast_atomic_fetchadd_int(&__mod_desc->usecnt, +1);
948 #endif
949         ast_update_use_count();
950         tmp->priority = 1;
951         /* Wake up and wait for other applications (by definition the login app)
952          * to release this channel). Takes ownership of the agent channel
953          * to this thread only.
954          * For signalling the other thread, ast_queue_frame is used until we
955          * can safely use signals for this purpose. The pselect() needs to be
956          * implemented in the kernel for this.
957          */
958         p->app_sleep_cond = 0;
959         if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) {
960                 if (p->chan) {
961                         ast_queue_frame(p->chan, &ast_null_frame);
962                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
963                         ast_mutex_lock(&p->app_lock);
964                         ast_mutex_lock(&p->lock);
965                 } else {
966                         ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
967                         p->owner = NULL;
968                         tmp->tech_pvt = NULL;
969                         p->app_sleep_cond = 1;
970                         ast_channel_free( tmp );
971                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
972                         ast_mutex_unlock(&p->app_lock);
973                         return NULL;
974                 }
975         } else if (!ast_strlen_zero(p->loginchan)) {
976                 if (p->chan)
977                         ast_queue_frame(p->chan, &ast_null_frame);
978                 if (!p->chan) {
979                         ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
980                         p->owner = NULL;
981                         tmp->tech_pvt = NULL;
982                         p->app_sleep_cond = 1;
983                         ast_channel_free( tmp );
984                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
985                         return NULL;
986                 }       
987         }
988                 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
989         p->owning_app = pthread_self();
990         /* After the above step, there should not be any blockers. */
991         if (p->chan) {
992                 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
993                         ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
994                         CRASH;
995                 }
996         }
997         return tmp;
998 }
999
1000
1001 /*!
1002  * Read configuration data. The file named agents.conf.
1003  *
1004  * \returns Always 0, or so it seems.
1005  */
1006 static int read_agent_config(void)
1007 {
1008         struct ast_config *cfg;
1009         struct ast_variable *v;
1010         struct agent_pvt *p;
1011         char *general_val;
1012
1013         group = 0;
1014         autologoff = 0;
1015         wrapuptime = 0;
1016         ackcall = 0;
1017         endcall = 1;
1018         cfg = ast_config_load(config);
1019         if (!cfg) {
1020                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1021                 return 0;
1022         }
1023         AST_LIST_LOCK(&agents);
1024         AST_LIST_TRAVERSE(&agents, p, list) {
1025                 p->dead = 1;
1026         }
1027         strcpy(moh, "default");
1028         /* set the default recording values */
1029         recordagentcalls = 0;
1030         strcpy(recordformat, "wav");
1031         strcpy(recordformatext, "wav");
1032         urlprefix[0] = '\0';
1033         savecallsin[0] = '\0';
1034
1035         /* Read in [general] section for persistence */
1036         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1037                 persistent_agents = ast_true(general_val);
1038         multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1039
1040         /* Read in the [agents] section */
1041         v = ast_variable_browse(cfg, "agents");
1042         while(v) {
1043                 /* Create the interface list */
1044                 if (!strcasecmp(v->name, "agent")) {
1045                         add_agent(v->value, 0);
1046                 } else if (!strcasecmp(v->name, "group")) {
1047                         group = ast_get_group(v->value);
1048                 } else if (!strcasecmp(v->name, "autologoff")) {
1049                         autologoff = atoi(v->value);
1050                         if (autologoff < 0)
1051                                 autologoff = 0;
1052                 } else if (!strcasecmp(v->name, "ackcall")) {
1053                         if (!strcasecmp(v->value, "always"))
1054                                 ackcall = 2;
1055                         else if (ast_true(v->value))
1056                                 ackcall = 1;
1057                         else
1058                                 ackcall = 0;
1059                 } else if (!strcasecmp(v->name, "endcall")) {
1060                         endcall = ast_true(v->value);
1061                 } else if (!strcasecmp(v->name, "wrapuptime")) {
1062                         wrapuptime = atoi(v->value);
1063                         if (wrapuptime < 0)
1064                                 wrapuptime = 0;
1065                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1066                         maxlogintries = atoi(v->value);
1067                         if (maxlogintries < 0)
1068                                 maxlogintries = 0;
1069                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1070                         strcpy(agentgoodbye,v->value);
1071                 } else if (!strcasecmp(v->name, "musiconhold")) {
1072                         ast_copy_string(moh, v->value, sizeof(moh));
1073                 } else if (!strcasecmp(v->name, "updatecdr")) {
1074                         if (ast_true(v->value))
1075                                 updatecdr = 1;
1076                         else
1077                                 updatecdr = 0;
1078                 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1079                         if (ast_true(v->value))
1080                                 autologoffunavail = 1;
1081                         else
1082                                 autologoffunavail = 0;
1083                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1084                         recordagentcalls = ast_true(v->value);
1085                 } else if (!strcasecmp(v->name, "recordformat")) {
1086                         ast_copy_string(recordformat, v->value, sizeof(recordformat));
1087                         if (!strcasecmp(v->value, "wav49"))
1088                                 strcpy(recordformatext, "WAV");
1089                         else
1090                                 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1091                 } else if (!strcasecmp(v->name, "urlprefix")) {
1092                         ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1093                         if (urlprefix[strlen(urlprefix) - 1] != '/')
1094                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1095                 } else if (!strcasecmp(v->name, "savecallsin")) {
1096                         if (v->value[0] == '/')
1097                                 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1098                         else
1099                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1100                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1101                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1102                 } else if (!strcasecmp(v->name, "custom_beep")) {
1103                         ast_copy_string(beep, v->value, sizeof(beep));
1104                 }
1105                 v = v->next;
1106         }
1107         AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1108                 if (p->dead) {
1109                         AST_LIST_REMOVE_CURRENT(&agents, list);
1110                         /* Destroy if  appropriate */
1111                         if (!p->owner) {
1112                                 if (!p->chan) {
1113                                         ast_mutex_destroy(&p->lock);
1114                                         ast_mutex_destroy(&p->app_lock);
1115                                         free(p);
1116                                 } else {
1117                                         /* Cause them to hang up */
1118                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1119                                 }
1120                         }
1121                 }
1122         }
1123         AST_LIST_TRAVERSE_SAFE_END
1124         AST_LIST_UNLOCK(&agents);
1125         ast_config_destroy(cfg);
1126         return 1;
1127 }
1128
1129 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1130 {
1131         struct ast_channel *chan=NULL, *parent=NULL;
1132         struct agent_pvt *p;
1133         int res;
1134
1135         if (option_debug)
1136                 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1137         if (needlock)
1138                 AST_LIST_LOCK(&agents);
1139         AST_LIST_TRAVERSE(&agents, p, list) {
1140                 if (p == newlyavailable) {
1141                         continue;
1142                 }
1143                 ast_mutex_lock(&p->lock);
1144                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1145                         if (option_debug)
1146                                 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1147                         /* We found a pending call, time to merge */
1148                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
1149                         parent = p->owner;
1150                         p->abouttograb = 1;
1151                         ast_mutex_unlock(&p->lock);
1152                         break;
1153                 }
1154                 ast_mutex_unlock(&p->lock);
1155         }
1156         if (needlock)
1157                 AST_LIST_UNLOCK(&agents);
1158         if (parent && chan)  {
1159                 if (newlyavailable->ackcall > 1) {
1160                         /* Don't do beep here */
1161                         res = 0;
1162                 } else {
1163                         if (option_debug > 2)
1164                                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1165                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1166                         if (option_debug > 2)
1167                                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1168                         if (!res) {
1169                                 res = ast_waitstream(newlyavailable->chan, "");
1170                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1171                         }
1172                 }
1173                 if (!res) {
1174                         /* Note -- parent may have disappeared */
1175                         if (p->abouttograb) {
1176                                 newlyavailable->acknowledged = 1;
1177                                 /* Safe -- agent lock already held */
1178                                 ast_setstate(parent, AST_STATE_UP);
1179                                 ast_setstate(chan, AST_STATE_UP);
1180                                 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1181                                 /* Go ahead and mark the channel as a zombie so that masquerade will
1182                                    destroy it for us, and we need not call ast_hangup */
1183                                 ast_mutex_lock(&parent->lock);
1184                                 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1185                                 ast_channel_masquerade(parent, chan);
1186                                 ast_mutex_unlock(&parent->lock);
1187                                 p->abouttograb = 0;
1188                         } else {
1189                                 if (option_debug)
1190                                         ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1191                                 agent_cleanup(newlyavailable);
1192                         }
1193                 } else {
1194                         if (option_debug)
1195                                 ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
1196                         agent_cleanup(newlyavailable);
1197                 }
1198         }
1199         return 0;
1200 }
1201
1202 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1203 {
1204         struct agent_pvt *p;
1205         int res=0;
1206
1207         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1208         if (needlock)
1209                 AST_LIST_LOCK(&agents);
1210         AST_LIST_TRAVERSE(&agents, p, list) {
1211                 if (p == newlyavailable) {
1212                         continue;
1213                 }
1214                 ast_mutex_lock(&p->lock);
1215                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1216                         if (option_debug)
1217                                 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1218                         ast_mutex_unlock(&p->lock);
1219                         break;
1220                 }
1221                 ast_mutex_unlock(&p->lock);
1222         }
1223         if (needlock)
1224                 AST_LIST_UNLOCK(&agents);
1225         if (p) {
1226                 ast_mutex_unlock(&newlyavailable->lock);
1227                 if (option_debug > 2)
1228                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1229                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1230                 if (option_debug > 2)
1231                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1232                 if (!res) {
1233                         res = ast_waitstream(newlyavailable->chan, "");
1234                         if (option_debug)
1235                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1236                 }
1237                 ast_mutex_lock(&newlyavailable->lock);
1238         }
1239         return res;
1240 }
1241
1242 /* 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. */
1243 static int allow_multiple_login(char *chan, char *context)
1244 {
1245         struct agent_pvt *p;
1246         char loginchan[80];
1247
1248         if(multiplelogin)
1249                 return 1;
1250         if(!chan) 
1251                 return 0;
1252
1253         snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, S_OR(context, "default"));
1254         
1255         AST_LIST_TRAVERSE(&agents, p, list) {
1256                 if(!strcasecmp(chan, p->loginchan))
1257                         return 0;
1258         }
1259         return -1;
1260 }
1261
1262 /*! \brief Part of the Asterisk PBX interface */
1263 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1264 {
1265         struct agent_pvt *p;
1266         struct ast_channel *chan = NULL;
1267         char *s;
1268         ast_group_t groupmatch;
1269         int groupoff;
1270         int waitforagent=0;
1271         int hasagent = 0;
1272         struct timeval tv;
1273
1274         s = data;
1275         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1276                 groupmatch = (1 << groupoff);
1277         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1278                 groupmatch = (1 << groupoff);
1279                 waitforagent = 1;
1280         } else 
1281                 groupmatch = 0;
1282
1283         /* Check actual logged in agents first */
1284         AST_LIST_LOCK(&agents);
1285         AST_LIST_TRAVERSE(&agents, p, list) {
1286                 ast_mutex_lock(&p->lock);
1287                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1288                     ast_strlen_zero(p->loginchan)) {
1289                         if (p->chan)
1290                                 hasagent++;
1291                         if (!p->lastdisc.tv_sec) {
1292                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1293                                 if (!p->owner && p->chan) {
1294                                         /* Fixed agent */
1295                                         chan = agent_new(p, AST_STATE_DOWN);
1296                                 }
1297                                 if (chan) {
1298                                         ast_mutex_unlock(&p->lock);
1299                                         break;
1300                                 }
1301                         }
1302                 }
1303                 ast_mutex_unlock(&p->lock);
1304         }
1305         if (!p) {
1306                 AST_LIST_TRAVERSE(&agents, p, list) {
1307                         ast_mutex_lock(&p->lock);
1308                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1309                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1310                                         hasagent++;
1311                                 tv = ast_tvnow();
1312 #if 0
1313                                 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1314 #endif
1315                                 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1316                                         p->lastdisc = ast_tv(0, 0);
1317                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1318                                         if (!p->owner && p->chan) {
1319                                                 /* Could still get a fixed agent */
1320                                                 chan = agent_new(p, AST_STATE_DOWN);
1321                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1322                                                 /* Adjustable agent */
1323                                                 p->chan = ast_request("Local", format, p->loginchan, cause);
1324                                                 if (p->chan)
1325                                                         chan = agent_new(p, AST_STATE_DOWN);
1326                                         }
1327                                         if (chan) {
1328                                                 ast_mutex_unlock(&p->lock);
1329                                                 break;
1330                                         }
1331                                 }
1332                         }
1333                         ast_mutex_unlock(&p->lock);
1334                 }
1335         }
1336
1337         if (!chan && waitforagent) {
1338                 /* No agent available -- but we're requesting to wait for one.
1339                    Allocate a place holder */
1340                 if (hasagent) {
1341                         if (option_debug)
1342                                 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1343                         p = add_agent(data, 1);
1344                         p->group = groupmatch;
1345                         chan = agent_new(p, AST_STATE_DOWN);
1346                         if (!chan) 
1347                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1348                 } else
1349                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1350         }
1351         *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1352         AST_LIST_UNLOCK(&agents);
1353         return chan;
1354 }
1355
1356 static force_inline int powerof(unsigned int d)
1357 {
1358         int x = ffs(d);
1359
1360         if (x)
1361                 return x - 1;
1362
1363         return 0;
1364 }
1365
1366 /*!
1367  * Lists agents and their status to the Manager API.
1368  * It is registered on load_module() and it gets called by the manager backend.
1369  * \param s
1370  * \param m
1371  * \returns 
1372  * \sa action_agent_logoff(), action_agent_callback_login(), load_module().
1373  */
1374 static int action_agents(struct mansession *s, struct message *m)
1375 {
1376         char *id = astman_get_header(m,"ActionID");
1377         char idText[256] = "";
1378         char chanbuf[256];
1379         struct agent_pvt *p;
1380         char *username = NULL;
1381         char *loginChan = NULL;
1382         char *talkingtoChan = NULL;
1383         char *status = NULL;
1384
1385         if (!ast_strlen_zero(id))
1386                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1387         astman_send_ack(s, m, "Agents will follow");
1388         AST_LIST_LOCK(&agents);
1389         AST_LIST_TRAVERSE(&agents, p, list) {
1390                 ast_mutex_lock(&p->lock);
1391
1392                 /* Status Values:
1393                    AGENT_LOGGEDOFF - Agent isn't logged in
1394                    AGENT_IDLE      - Agent is logged in, and waiting for call
1395                    AGENT_ONCALL    - Agent is logged in, and on a call
1396                    AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1397
1398                 username = S_OR(p->name, "None");
1399
1400                 /* Set a default status. It 'should' get changed. */
1401                 status = "AGENT_UNKNOWN";
1402
1403                 if (!ast_strlen_zero(p->loginchan) && !p->chan) {
1404                         loginChan = p->loginchan;
1405                         talkingtoChan = "n/a";
1406                         status = "AGENT_IDLE";
1407                         if (p->acknowledged) {
1408                                 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
1409                                 loginChan = chanbuf;
1410                         }
1411                 } else if (p->chan) {
1412                         loginChan = ast_strdupa(p->chan->name);
1413                         if (p->owner && p->owner->_bridge) {
1414                                 talkingtoChan = p->chan->cid.cid_num;
1415                                 status = "AGENT_ONCALL";
1416                         } else {
1417                                 talkingtoChan = "n/a";
1418                                 status = "AGENT_IDLE";
1419                         }
1420                 } else {
1421                         loginChan = "n/a";
1422                         talkingtoChan = "n/a";
1423                         status = "AGENT_LOGGEDOFF";
1424                 }
1425
1426                 astman_append(s, "Event: Agents\r\n"
1427                         "Agent: %s\r\n"
1428                         "Name: %s\r\n"
1429                         "Status: %s\r\n"
1430                         "LoggedInChan: %s\r\n"
1431                         "LoggedInTime: %d\r\n"
1432                         "TalkingTo: %s\r\n"
1433                         "%s"
1434                         "\r\n",
1435                         p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
1436                 ast_mutex_unlock(&p->lock);
1437         }
1438         AST_LIST_UNLOCK(&agents);
1439         astman_append(s, "Event: AgentsComplete\r\n"
1440                 "%s"
1441                 "\r\n",idText);
1442         return 0;
1443 }
1444
1445 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
1446 {
1447         char *tmp = NULL;
1448         char agent[AST_MAX_AGENT];
1449
1450         if (!ast_strlen_zero(logcommand))
1451                 tmp = logcommand;
1452         else
1453                 tmp = ast_strdupa("");
1454
1455         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1456
1457         if (!ast_strlen_zero(uniqueid)) {
1458                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1459                                 "Agent: %s\r\n"
1460                                 "Reason: %s\r\n"
1461                                 "Loginchan: %s\r\n"
1462                                 "Logintime: %ld\r\n"
1463                                 "Uniqueid: %s\r\n", 
1464                                 p->agent, tmp, loginchan, logintime, uniqueid);
1465         } else {
1466                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1467                                 "Agent: %s\r\n"
1468                                 "Reason: %s\r\n"
1469                                 "Loginchan: %s\r\n"
1470                                 "Logintime: %ld\r\n",
1471                                 p->agent, tmp, loginchan, logintime);
1472         }
1473
1474         ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
1475         set_agentbycallerid(p->logincallerid, NULL);
1476         p->loginchan[0] ='\0';
1477         p->logincallerid[0] = '\0';
1478         ast_device_state_changed("Agent/%s", p->agent);
1479         if (persistent_agents)
1480                 dump_agents();  
1481
1482 }
1483
1484 static int agent_logoff(char *agent, int soft)
1485 {
1486         struct agent_pvt *p;
1487         long logintime;
1488         int ret = -1; /* Return -1 if no agent if found */
1489
1490         AST_LIST_TRAVERSE(&agents, p, list) {
1491                 if (!strcasecmp(p->agent, agent)) {
1492                         if (!soft) {
1493                                 if (p->owner)
1494                                         ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1495                                 if (p->chan) 
1496                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1497                         }
1498                         ret = 0; /* found an agent => return 0 */
1499                         logintime = time(NULL) - p->loginstart;
1500                         p->loginstart = 0;
1501                         agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
1502                         break;
1503                 }
1504         }
1505
1506         return ret;
1507 }
1508
1509 static int agent_logoff_cmd(int fd, int argc, char **argv)
1510 {
1511         int ret;
1512         char *agent;
1513
1514         if (argc < 3 || argc > 4)
1515                 return RESULT_SHOWUSAGE;
1516         if (argc == 4 && strcasecmp(argv[3], "soft"))
1517                 return RESULT_SHOWUSAGE;
1518
1519         agent = argv[2] + 6;
1520         ret = agent_logoff(agent, argc == 4);
1521         if (ret == 0)
1522                 ast_cli(fd, "Logging out %s\n", agent);
1523
1524         return RESULT_SUCCESS;
1525 }
1526
1527 /*!
1528  * Sets an agent as no longer logged in in the Manager API.
1529  * It is registered on load_module() and it gets called by the manager backend.
1530  * \param s
1531  * \param m
1532  * \returns 
1533  * \sa action_agents(), action_agent_callback_login(), load_module().
1534  */
1535 static int action_agent_logoff(struct mansession *s, struct message *m)
1536 {
1537         char *agent = astman_get_header(m, "Agent");
1538         char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1539         int soft;
1540         int ret; /* return value of agent_logoff */
1541
1542         if (ast_strlen_zero(agent)) {
1543                 astman_send_error(s, m, "No agent specified");
1544                 return 0;
1545         }
1546
1547         soft = ast_true(soft_s) ? 1 : 0;
1548         ret = agent_logoff(agent, soft);
1549         if (ret == 0)
1550                 astman_send_ack(s, m, "Agent logged out");
1551         else
1552                 astman_send_error(s, m, "No such agent");
1553
1554         return 0;
1555 }
1556
1557 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1558 {
1559         if (pos == 2) {
1560                 struct agent_pvt *p;
1561                 char name[AST_MAX_AGENT];
1562                 int which = 0, len = strlen(word);
1563
1564                 AST_LIST_TRAVERSE(&agents, p, list) {
1565                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1566                         if (!strncasecmp(word, name, len) && ++which > state)
1567                                 return ast_strdup(name);
1568                 }
1569         } else if (pos == 3 && state == 0) 
1570                 return ast_strdup("soft");
1571         
1572         return NULL;
1573 }
1574
1575 /*!
1576  * Show agents in cli.
1577  */
1578 static int agents_show(int fd, int argc, char **argv)
1579 {
1580         struct agent_pvt *p;
1581         char username[AST_MAX_BUF];
1582         char location[AST_MAX_BUF] = "";
1583         char talkingto[AST_MAX_BUF] = "";
1584         char moh[AST_MAX_BUF];
1585         int count_agents = 0;           /*!< Number of agents configured */
1586         int online_agents = 0;          /*!< Number of online agents */
1587         int offline_agents = 0;         /*!< Number of offline agents */
1588         if (argc != 2)
1589                 return RESULT_SHOWUSAGE;
1590         AST_LIST_LOCK(&agents);
1591         AST_LIST_TRAVERSE(&agents, p, list) {
1592                 ast_mutex_lock(&p->lock);
1593                 if (p->pending) {
1594                         if (p->group)
1595                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1596                         else
1597                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1598                 } else {
1599                         if (!ast_strlen_zero(p->name))
1600                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1601                         else
1602                                 username[0] = '\0';
1603                         if (p->chan) {
1604                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1605                                 if (p->owner && ast_bridged_channel(p->owner))
1606                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1607                                  else 
1608                                         strcpy(talkingto, " is idle");
1609                                 online_agents++;
1610                         } else if (!ast_strlen_zero(p->loginchan)) {
1611                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
1612                                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1613                                 else 
1614                                         snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
1615                                 talkingto[0] = '\0';
1616                                 online_agents++;
1617                                 if (p->acknowledged)
1618                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1619                         } else {
1620                                 strcpy(location, "not logged in");
1621                                 talkingto[0] = '\0';
1622                                 offline_agents++;
1623                         }
1624                         if (!ast_strlen_zero(p->moh))
1625                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1626                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1627                                 username, location, talkingto, moh);
1628                         count_agents++;
1629                 }
1630                 ast_mutex_unlock(&p->lock);
1631         }
1632         AST_LIST_UNLOCK(&agents);
1633         if ( !count_agents ) 
1634                 ast_cli(fd, "No Agents are configured in %s\n",config);
1635         else 
1636                 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1637         ast_cli(fd, "\n");
1638                         
1639         return RESULT_SUCCESS;
1640 }
1641
1642
1643 static int agents_show_online(int fd, int argc, char **argv)
1644 {
1645         struct agent_pvt *p;
1646         char username[AST_MAX_BUF];
1647         char location[AST_MAX_BUF] = "";
1648         char talkingto[AST_MAX_BUF] = "";
1649         char moh[AST_MAX_BUF];
1650         int count_agents = 0;           /* Number of agents configured */
1651         int online_agents = 0;          /* Number of online agents */
1652         int agent_status = 0;           /* 0 means offline, 1 means online */
1653         if (argc != 3)
1654                 return RESULT_SHOWUSAGE;
1655         AST_LIST_LOCK(&agents);
1656         AST_LIST_TRAVERSE(&agents, p, list) {
1657                 agent_status = 0;       /* reset it to offline */
1658                 ast_mutex_lock(&p->lock);
1659                 if (!ast_strlen_zero(p->name))
1660                         snprintf(username, sizeof(username), "(%s) ", p->name);
1661                 else
1662                         username[0] = '\0';
1663                 if (p->chan) {
1664                         snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1665                         if (p->owner && ast_bridged_channel(p->owner)) 
1666                                 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1667                         else 
1668                                 strcpy(talkingto, " is idle");
1669                         agent_status = 1;
1670                         online_agents++;
1671                 } else if (!ast_strlen_zero(p->loginchan)) {
1672                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1673                         talkingto[0] = '\0';
1674                         agent_status = 1;
1675                         online_agents++;
1676                         if (p->acknowledged)
1677                                 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1678                 }
1679                 if (!ast_strlen_zero(p->moh))
1680                         snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1681                 if (agent_status)
1682                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
1683                 count_agents++;
1684                 ast_mutex_unlock(&p->lock);
1685         }
1686         AST_LIST_UNLOCK(&agents);
1687         if (!count_agents) 
1688                 ast_cli(fd, "No Agents are configured in %s\n", config);
1689         else
1690                 ast_cli(fd, "%d agents online\n", online_agents);
1691         ast_cli(fd, "\n");
1692         return RESULT_SUCCESS;
1693 }
1694
1695
1696
1697 static char show_agents_usage[] = 
1698 "Usage: agent list\n"
1699 "       Provides summary information on agents.\n";
1700
1701 static char show_agents_online_usage[] =
1702 "Usage: agent list online\n"
1703 "       Provides a list of all online agents.\n";
1704
1705 static char agent_logoff_usage[] =
1706 "Usage: agent logoff <channel> [soft]\n"
1707 "       Sets an agent as no longer logged in.\n"
1708 "       If 'soft' is specified, do not hangup existing calls.\n";
1709
1710 static struct ast_cli_entry cli_show_agents_deprecated = {
1711         { "show", "agents", NULL },
1712         agents_show, NULL,
1713         NULL, NULL };
1714
1715 static struct ast_cli_entry cli_show_agents_online_deprecated = {
1716         { "show", "agents", "online" },
1717         agents_show_online, NULL,
1718         NULL, NULL };
1719
1720 static struct ast_cli_entry cli_agents[] = {
1721         { { "agent", "list", NULL },
1722         agents_show, "Show status of agents",
1723         show_agents_usage, NULL, &cli_show_agents_deprecated },
1724
1725         { { "agent", "list", "online" },
1726         agents_show_online, "Show all online agents",
1727         show_agents_online_usage, NULL, &cli_show_agents_online_deprecated },
1728
1729         { { "agent", "logoff", NULL },
1730         agent_logoff_cmd, "Sets an agent offline",
1731         agent_logoff_usage, complete_agent_logoff_cmd },
1732 };
1733
1734 /*!
1735  * \brief Log in agent application.
1736  *
1737  * \param chan
1738  * \param data
1739  * \param callbackmode non-zero for AgentCallbackLogin
1740  */
1741 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1742 {
1743         int res=0;
1744         int tries = 0;
1745         int max_login_tries = maxlogintries;
1746         struct agent_pvt *p;
1747         struct ast_module_user *u;
1748         int login_state = 0;
1749         char user[AST_MAX_AGENT] = "";
1750         char pass[AST_MAX_AGENT];
1751         char agent[AST_MAX_AGENT] = "";
1752         char xpass[AST_MAX_AGENT] = "";
1753         char *errmsg;
1754         char *parse;
1755         AST_DECLARE_APP_ARGS(args,
1756                              AST_APP_ARG(agent_id);
1757                              AST_APP_ARG(options);
1758                              AST_APP_ARG(extension);
1759                 );
1760         const char *tmpoptions = NULL;
1761         char *context = NULL;
1762         int play_announcement = 1;
1763         char agent_goodbye[AST_MAX_FILENAME_LEN];
1764         int update_cdr = updatecdr;
1765         char *filename = "agent-loginok";
1766         char tmpchan[AST_MAX_BUF] = "";
1767
1768         u = ast_module_user_add(chan);
1769
1770         parse = ast_strdupa(data);
1771
1772         AST_STANDARD_APP_ARGS(args, parse);
1773
1774         ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1775
1776         /* Set Channel Specific Login Overrides */
1777         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1778                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1779                 if (max_login_tries < 0)
1780                         max_login_tries = 0;
1781                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1782                 if (option_verbose > 2)
1783                         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);
1784         }
1785         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1786                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1787                         update_cdr = 1;
1788                 else
1789                         update_cdr = 0;
1790                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1791                 if (option_verbose > 2)
1792                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1793         }
1794         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1795                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1796                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1797                 if (option_verbose > 2)
1798                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1799         }
1800         /* End Channel Specific Login Overrides */
1801         
1802         if (callbackmode && args.extension) {
1803                 parse = args.extension;
1804                 args.extension = strsep(&parse, "@");
1805                 context = parse;
1806         }
1807
1808         if (!ast_strlen_zero(args.options)) {
1809                 if (strchr(args.options, 's')) {
1810                         play_announcement = 0;
1811                 }
1812         }
1813
1814         if (chan->_state != AST_STATE_UP)
1815                 res = ast_answer(chan);
1816         if (!res) {
1817                 if (!ast_strlen_zero(args.agent_id))
1818                         ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1819                 else
1820                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1821         }
1822         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1823                 tries++;
1824                 /* Check for password */
1825                 AST_LIST_LOCK(&agents);
1826                 AST_LIST_TRAVERSE(&agents, p, list) {
1827                         if (!strcmp(p->agent, user) && !p->pending)
1828                                 ast_copy_string(xpass, p->password, sizeof(xpass));
1829                 }
1830                 AST_LIST_UNLOCK(&agents);
1831                 if (!res) {
1832                         if (!ast_strlen_zero(xpass))
1833                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1834                         else
1835                                 pass[0] = '\0';
1836                 }
1837                 errmsg = "agent-incorrect";
1838
1839 #if 0
1840                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1841 #endif          
1842
1843                 /* Check again for accuracy */
1844                 AST_LIST_LOCK(&agents);
1845                 AST_LIST_TRAVERSE(&agents, p, list) {
1846                         ast_mutex_lock(&p->lock);
1847                         if (!strcmp(p->agent, user) &&
1848                             !strcmp(p->password, pass) && !p->pending) {
1849                                 login_state = 1; /* Successful Login */
1850
1851                                 /* Ensure we can't be gotten until we're done */
1852                                 gettimeofday(&p->lastdisc, NULL);
1853                                 p->lastdisc.tv_sec++;
1854
1855                                 /* Set Channel Specific Agent Overrides */
1856                                 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1857                                         if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1858                                                 p->ackcall = 2;
1859                                         else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1860                                                 p->ackcall = 1;
1861                                         else
1862                                                 p->ackcall = 0;
1863                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1864                                         if (option_verbose > 2)
1865                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1866                                 }
1867                                 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1868                                         p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1869                                         if (p->autologoff < 0)
1870                                                 p->autologoff = 0;
1871                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1872                                         if (option_verbose > 2)
1873                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1874                                 }
1875                                 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1876                                         p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1877                                         if (p->wrapuptime < 0)
1878                                                 p->wrapuptime = 0;
1879                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1880                                         if (option_verbose > 2)
1881                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1882                                 }
1883                                 /* End Channel Specific Agent Overrides */
1884                                 if (!p->chan) {
1885                                         char last_loginchan[80] = "";
1886                                         long logintime;
1887                                         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1888
1889                                         if (callbackmode) {
1890                                                 int pos = 0;
1891                                                 /* Retrieve login chan */
1892                                                 for (;;) {
1893                                                         if (!ast_strlen_zero(args.extension)) {
1894                                                                 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
1895                                                                 res = 0;
1896                                                         } else
1897                                                                 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1898                                                         if (ast_strlen_zero(tmpchan) )
1899                                                                 break;
1900                                                         if(ast_exists_extension(chan, S_OR(context,"default"), tmpchan,1, NULL) ) {
1901                                                                 if(!allow_multiple_login(tmpchan,context) ) {
1902                                                                         args.extension = NULL;
1903                                                                         pos = 0;
1904                                                                 } else
1905                                                                         break;
1906                                                         }
1907                                                         if (args.extension) {
1908                                                                 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
1909                                                                 args.extension = NULL;
1910                                                                 pos = 0;
1911                                                         } else {
1912                                                                 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, S_OR(context, "default"), p->agent);
1913                                                                 res = ast_streamfile(chan, "invalid", chan->language);
1914                                                                 if (!res)
1915                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
1916                                                                 if (res > 0) {
1917                                                                         tmpchan[0] = res;
1918                                                                         tmpchan[1] = '\0';
1919                                                                         pos = 1;
1920                                                                 } else {
1921                                                                         tmpchan[0] = '\0';
1922                                                                         pos = 0;
1923                                                                 }
1924                                                         }
1925                                                 }
1926                                                 args.extension = tmpchan;
1927                                                 if (!res) {
1928                                                         set_agentbycallerid(p->logincallerid, NULL);
1929                                                         if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1930                                                                 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1931                                                         else {
1932                                                                 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1933                                                                 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1934                                                         }
1935                                                         p->acknowledged = 0;
1936                                                         if (ast_strlen_zero(p->loginchan)) {
1937                                                                 login_state = 2;
1938                                                                 filename = "agent-loggedoff";
1939                                                         } else {
1940                                                                 if (chan->cid.cid_num) {
1941                                                                         ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1942                                                                         set_agentbycallerid(p->logincallerid, p->agent);
1943                                                                 } else
1944                                                                         p->logincallerid[0] = '\0';
1945                                                         }
1946
1947                                                         if(update_cdr && chan->cdr)
1948                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1949
1950                                                 }
1951                                         } else {
1952                                                 p->loginchan[0] = '\0';
1953                                                 p->logincallerid[0] = '\0';
1954                                                 p->acknowledged = 0;
1955                                         }
1956                                         ast_mutex_unlock(&p->lock);
1957                                         AST_LIST_UNLOCK(&agents);
1958                                         if( !res && play_announcement==1 )
1959                                                 res = ast_streamfile(chan, filename, chan->language);
1960                                         if (!res)
1961                                                 ast_waitstream(chan, "");
1962                                         AST_LIST_LOCK(&agents);
1963                                         ast_mutex_lock(&p->lock);
1964                                         if (!res) {
1965                                                 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1966                                                 if (res)
1967                                                         ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1968                                         }
1969                                         if (!res) {
1970                                                 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1971                                                 if (res)
1972                                                         ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1973                                         }
1974                                         /* Check once more just in case */
1975                                         if (p->chan)
1976                                                 res = -1;
1977                                         if (callbackmode && !res) {
1978                                                 /* Just say goodbye and be done with it */
1979                                                 if (!ast_strlen_zero(p->loginchan)) {
1980                                                         if (p->loginstart == 0)
1981                                                                 time(&p->loginstart);
1982                                                         manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1983                                                                       "Agent: %s\r\n"
1984                                                                       "Loginchan: %s\r\n"
1985                                                                       "Uniqueid: %s\r\n",
1986                                                                       p->agent, p->loginchan, chan->uniqueid);
1987                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1988                                                         if (option_verbose > 1)
1989                                                                 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1990                                                         ast_device_state_changed("Agent/%s", p->agent);
1991                                                         if (persistent_agents)
1992                                                                 dump_agents();
1993                                                 } else {
1994                                                         logintime = time(NULL) - p->loginstart;
1995                                                         p->loginstart = 0;
1996
1997                                                         agent_logoff_maintenance(p, last_loginchan, logintime, chan->uniqueid, NULL);
1998                                                         if (option_verbose > 1)
1999                                                                 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
2000                                                 }
2001                                                 AST_LIST_UNLOCK(&agents);
2002                                                 if (!res)
2003                                                         res = ast_safe_sleep(chan, 500);
2004                                                 ast_mutex_unlock(&p->lock);
2005                                         } else if (!res) {
2006                                                 ast_indicate_data(chan, AST_CONTROL_HOLD, 
2007                                                         S_OR(p->moh, NULL), 
2008                                                         !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2009                                                 if (p->loginstart == 0)
2010                                                         time(&p->loginstart);
2011                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2012                                                               "Agent: %s\r\n"
2013                                                               "Channel: %s\r\n"
2014                                                               "Uniqueid: %s\r\n",
2015                                                               p->agent, chan->name, chan->uniqueid);
2016                                                 if (update_cdr && chan->cdr)
2017                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2018                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
2019                                                 if (option_verbose > 1)
2020                                                         ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
2021                                                                     ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
2022                                                 /* Login this channel and wait for it to go away */
2023                                                 p->chan = chan;
2024                                                 if (p->ackcall > 1)
2025                                                         check_beep(p, 0);
2026                                                 else
2027                                                         check_availability(p, 0);
2028                                                 ast_mutex_unlock(&p->lock);
2029                                                 AST_LIST_UNLOCK(&agents);
2030                                                 ast_device_state_changed("Agent/%s", p->agent);
2031                                                 while (res >= 0) {
2032                                                         ast_mutex_lock(&p->lock);
2033                                                         if (p->chan != chan)
2034                                                                 res = -1;
2035                                                         ast_mutex_unlock(&p->lock);
2036                                                         /* Yield here so other interested threads can kick in. */
2037                                                         sched_yield();
2038                                                         if (res)
2039                                                                 break;
2040
2041                                                         AST_LIST_LOCK(&agents);
2042                                                         ast_mutex_lock(&p->lock);
2043                                                         if (p->lastdisc.tv_sec) {
2044                                                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
2045                                                                         if (option_debug)
2046                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
2047                                                                         p->lastdisc = ast_tv(0, 0);
2048                                                                         if (p->ackcall > 1)
2049                                                                                 check_beep(p, 0);
2050                                                                         else
2051                                                                                 check_availability(p, 0);
2052                                                                 }
2053                                                         }
2054                                                         ast_mutex_unlock(&p->lock);
2055                                                         AST_LIST_UNLOCK(&agents);
2056                                                         /*      Synchronize channel ownership between call to agent and itself. */
2057                                                         ast_mutex_lock( &p->app_lock );
2058                                                         ast_mutex_lock(&p->lock);
2059                                                         p->owning_app = pthread_self();
2060                                                         ast_mutex_unlock(&p->lock);
2061                                                         if (p->ackcall > 1) 
2062                                                                 res = agent_ack_sleep(p);
2063                                                         else
2064                                                                 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2065                                                         ast_mutex_unlock( &p->app_lock );
2066                                                         if ((p->ackcall > 1)  && (res == 1)) {
2067                                                                 AST_LIST_LOCK(&agents);
2068                                                                 ast_mutex_lock(&p->lock);
2069                                                                 check_availability(p, 0);
2070                                                                 ast_mutex_unlock(&p->lock);
2071                                                                 AST_LIST_UNLOCK(&agents);
2072                                                                 res = 0;
2073                                                         }
2074                                                         sched_yield();
2075                                                 }
2076                                                 ast_mutex_lock(&p->lock);
2077                                                 if (res && p->owner) 
2078                                                         ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
2079                                                 /* Log us off if appropriate */
2080                                                 if (p->chan == chan)
2081                                                         p->chan = NULL;
2082                                                 p->acknowledged = 0;
2083                                                 logintime = time(NULL) - p->loginstart;
2084                                                 p->loginstart = 0;
2085                                                 ast_mutex_unlock(&p->lock);
2086                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2087                                                               "Agent: %s\r\n"
2088                                                               "Logintime: %ld\r\n"
2089                                                               "Uniqueid: %s\r\n",
2090                                                               p->agent, logintime, chan->uniqueid);
2091                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2092                                                 if (option_verbose > 1)
2093                                                         ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
2094                                                 /* If there is no owner, go ahead and kill it now */
2095                                                 ast_device_state_changed("Agent/%s", p->agent);
2096                                                 if (p->dead && !p->owner) {
2097                                                         ast_mutex_destroy(&p->lock);
2098                                                         ast_mutex_destroy(&p->app_lock);
2099                                                         free(p);
2100                                                 }
2101                                         }
2102                                         else {
2103                                                 ast_mutex_unlock(&p->lock);
2104                                                 p = NULL;
2105                                         }
2106                                         res = -1;
2107                                 } else {
2108                                         ast_mutex_unlock(&p->lock);
2109                                         errmsg = "agent-alreadyon";
2110                                         p = NULL;
2111                                 }
2112                                 break;
2113                         }
2114                         ast_mutex_unlock(&p->lock);
2115                 }
2116                 if (!p)
2117                         AST_LIST_UNLOCK(&agents);
2118
2119                 if (!res && (max_login_tries==0 || tries < max_login_tries))
2120                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2121         }
2122                 
2123         if (!res)
2124                 res = ast_safe_sleep(chan, 500);
2125
2126         /* AgentLogin() exit */
2127         if (!callbackmode) {
2128                 ast_module_user_remove(u);
2129                 return -1;
2130         } else { /* AgentCallbackLogin() exit*/
2131                 /* Set variables */
2132                 if (login_state > 0) {
2133                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
2134                         if (login_state==1) {
2135                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
2136                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
2137                         } else 
2138                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
2139                 } else {
2140                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
2141                 }
2142                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
2143                         ast_module_user_remove(u);
2144                         return 0;
2145                 }
2146                 /* Do we need to play agent-goodbye now that we will be hanging up? */
2147                 if (play_announcement) {
2148                         if (!res)
2149                                 res = ast_safe_sleep(chan, 1000);
2150                         res = ast_streamfile(chan, agent_goodbye, chan->language);
2151                         if (!res)
2152                                 res = ast_waitstream(chan, "");
2153                         if (!res)
2154                                 res = ast_safe_sleep(chan, 1000);
2155                 }
2156         }
2157
2158         ast_module_user_remove(u);
2159         
2160         /* We should never get here if next priority exists when in callbackmode */
2161         return -1;
2162 }
2163
2164 /*!
2165  * Called by the AgentLogin application (from the dial plan).
2166  * 
2167  * \param chan
2168  * \param data
2169  * \returns
2170  * \sa callback_login_exec(), agentmonitoroutgoing_exec(), load_module().
2171  */
2172 static int login_exec(struct ast_channel *chan, void *data)
2173 {
2174         return __login_exec(chan, data, 0);
2175 }
2176
2177 static void callback_deprecated(void)
2178 {
2179         static int depwarning = 0;
2180
2181         if (!depwarning) {
2182                 depwarning = 1;
2183
2184                 ast_log(LOG_WARNING, "AgentCallbackLogin is deprecated and will be removed in a future release.\n");
2185                 ast_log(LOG_WARNING, "See doc/queues-with-callback-members.txt for an example of how to achieve\n");
2186                 ast_log(LOG_WARNING, "the same functionality using only dialplan logic.\n");
2187         }
2188 }
2189
2190 /*!
2191  *  Called by the AgentCallbackLogin application (from the dial plan).
2192  * 
2193  * \param chan
2194  * \param data
2195  * \returns
2196  * \sa login_exec(), agentmonitoroutgoing_exec(), load_module().
2197  */
2198 static int callback_exec(struct ast_channel *chan, void *data)
2199 {
2200         callback_deprecated();
2201
2202         return __login_exec(chan, data, 1);
2203 }
2204
2205 /*!
2206  * Sets an agent as logged in by callback in the Manager API.
2207  * It is registered on load_module() and it gets called by the manager backend.
2208  * \param s
2209  * \param m
2210  * \returns 
2211  * \sa action_agents(), action_agent_logoff(), load_module().
2212  */
2213 static int action_agent_callback_login(struct mansession *s, struct message *m)
2214 {
2215         char *agent = astman_get_header(m, "Agent");
2216         char *exten = astman_get_header(m, "Exten");
2217         char *context = astman_get_header(m, "Context");
2218         char *wrapuptime_s = astman_get_header(m, "WrapupTime");
2219         char *ackcall_s = astman_get_header(m, "AckCall");
2220         struct agent_pvt *p;
2221         int login_state = 0;
2222
2223         callback_deprecated();
2224
2225         if (ast_strlen_zero(agent)) {
2226                 astman_send_error(s, m, "No agent specified");
2227                 return 0;
2228         }
2229
2230         if (ast_strlen_zero(exten)) {
2231                 astman_send_error(s, m, "No extension specified");
2232                 return 0;
2233         }
2234
2235         AST_LIST_LOCK(&agents);
2236         AST_LIST_TRAVERSE(&agents, p, list) {
2237                 if (strcmp(p->agent, agent) || p->pending) 
2238                         continue;
2239                 if (p->chan) {
2240                         login_state = 2; /* already logged in (and on the phone)*/
2241                         break;
2242                 }
2243                 ast_mutex_lock(&p->lock);
2244                 login_state = 1; /* Successful Login */
2245                 
2246                 if (ast_strlen_zero(context))
2247                         ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
2248                 else
2249                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
2250
2251                 if (!ast_strlen_zero(wrapuptime_s)) {
2252                         p->wrapuptime = atoi(wrapuptime_s);
2253                         if (p->wrapuptime < 0)
2254                                 p->wrapuptime = 0;
2255                 }
2256
2257                 if (ast_true(ackcall_s))
2258                         p->ackcall = 1;
2259                 else
2260                         p->ackcall = 0;
2261
2262                 if (p->loginstart == 0)
2263                         time(&p->loginstart);
2264                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
2265                               "Agent: %s\r\n"
2266                               "Loginchan: %s\r\n",
2267                               p->agent, p->loginchan);
2268                 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
2269                 if (option_verbose > 1)
2270                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
2271                 ast_device_state_changed("Agent/%s", p->agent);
2272                 ast_mutex_unlock(&p->lock);
2273                 if (persistent_agents)
2274                         dump_agents();
2275         }
2276         AST_LIST_UNLOCK(&agents);
2277
2278         if (login_state == 1)
2279                 astman_send_ack(s, m, "Agent logged in");
2280         else if (login_state == 0)
2281                 astman_send_error(s, m, "No such agent");
2282         else if (login_state == 2)
2283                 astman_send_error(s, m, "Agent already logged in");
2284
2285         return 0;
2286 }
2287
2288 /*!
2289  *  \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2290  *
2291  * \param chan
2292  * \param data
2293  * \returns
2294  * \sa login_exec(), callback_login_exec(), load_module().
2295  */
2296 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2297 {
2298         int exitifnoagentid = 0;
2299         int nowarnings = 0;
2300         int changeoutgoing = 0;
2301         int res = 0;
2302         char agent[AST_MAX_AGENT];
2303
2304         if (data) {
2305                 if (strchr(data, 'd'))
2306                         exitifnoagentid = 1;
2307                 if (strchr(data, 'n'))
2308                         nowarnings = 1;
2309                 if (strchr(data, 'c'))
2310                         changeoutgoing = 1;
2311         }
2312         if (chan->cid.cid_num) {
2313                 const char *tmp;
2314                 char agentvar[AST_MAX_BUF];
2315                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2316                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2317                         struct agent_pvt *p;
2318                         ast_copy_string(agent, tmp, sizeof(agent));
2319                         AST_LIST_LOCK(&agents);
2320                         AST_LIST_TRAVERSE(&agents, p, list) {
2321                                 if (!strcasecmp(p->agent, tmp)) {
2322                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2323                                         __agent_start_monitoring(chan, p, 1);
2324                                         break;
2325                                 }
2326                         }
2327                         AST_LIST_UNLOCK(&agents);
2328                         
2329                 } else {
2330                         res = -1;
2331                         if (!nowarnings)
2332                                 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);
2333                 }
2334         } else {
2335                 res = -1;
2336                 if (!nowarnings)
2337                         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");
2338         }
2339         /* check if there is n + 101 priority */
2340         /*! \todo XXX Needs to check option priorityjump etc etc */
2341         if (res) {
2342                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2343                         chan->priority+=100;
2344                         if (option_verbose > 2)
2345                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2346                 } else if (exitifnoagentid)
2347                         return res;
2348         }
2349         return 0;
2350 }
2351
2352 /*!
2353  * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
2354  */
2355 static void dump_agents(void)
2356 {
2357         struct agent_pvt *cur_agent = NULL;
2358         char buf[256];
2359
2360         AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2361                 if (cur_agent->chan)
2362                         continue;
2363
2364                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2365                         snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2366                         if (ast_db_put(pa_family, cur_agent->agent, buf))
2367                                 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
2368                         else if (option_debug)
2369                                 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2370                 } else {
2371                         /* Delete -  no agent or there is an error */
2372                         ast_db_del(pa_family, cur_agent->agent);
2373                 }
2374         }
2375 }
2376
2377 /*!
2378  * \brief Reload the persistent agents from astdb.
2379  */
2380 static void reload_agents(void)
2381 {
2382         char *agent_num;
2383         struct ast_db_entry *db_tree;
2384         struct ast_db_entry *entry;
2385         struct agent_pvt *cur_agent;
2386         char agent_data[256];
2387         char *parse;
2388         char *agent_chan;
2389         char *agent_callerid;
2390
2391         db_tree = ast_db_gettree(pa_family, NULL);
2392
2393         AST_LIST_LOCK(&agents);
2394         for (entry = db_tree; entry; entry = entry->next) {
2395                 agent_num = entry->key + strlen(pa_family) + 2;
2396                 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2397                         ast_mutex_lock(&cur_agent->lock);
2398                         if (strcmp(agent_num, cur_agent->agent) == 0)
2399                                 break;
2400                         ast_mutex_unlock(&cur_agent->lock);
2401                 }
2402                 if (!cur_agent) {
2403                         ast_db_del(pa_family, agent_num);
2404                         continue;
2405                 } else
2406                         ast_mutex_unlock(&cur_agent->lock);
2407                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2408                         if (option_debug)
2409                                 ast_log(LOG_DEBUG, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
2410                         parse = agent_data;
2411                         agent_chan = strsep(&parse, ";");
2412                         agent_callerid = strsep(&parse, ";");
2413                         ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2414                         if (agent_callerid) {
2415                                 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2416                                 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2417                         } else
2418                                 cur_agent->logincallerid[0] = '\0';
2419                         if (cur_agent->loginstart == 0)
2420                                 time(&cur_agent->loginstart);
2421                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2422                 }
2423         }
2424         AST_LIST_UNLOCK(&agents);
2425         if (db_tree) {
2426                 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
2427                 ast_db_freetree(db_tree);
2428         }
2429 }
2430
2431 /*! \brief Part of PBX channel interface */
2432 static int agent_devicestate(void *data)
2433 {
2434         struct agent_pvt *p;
2435         char *s;
2436         ast_group_t groupmatch;
2437         int groupoff;
2438         int waitforagent=0;
2439         int res = AST_DEVICE_INVALID;
2440         
2441         s = data;
2442         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
2443                 groupmatch = (1 << groupoff);
2444         else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2445                 groupmatch = (1 << groupoff);
2446                 waitforagent = 1;
2447         } else 
2448                 groupmatch = 0;
2449
2450         /* Check actual logged in agents first */
2451         AST_LIST_LOCK(&agents);
2452         AST_LIST_TRAVERSE(&agents, p, list) {
2453                 ast_mutex_lock(&p->lock);
2454                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2455                         if (p->owner) {
2456                                 if (res != AST_DEVICE_INUSE)
2457                                         res = AST_DEVICE_BUSY;
2458                         } else {
2459                                 if (res == AST_DEVICE_BUSY)
2460                                         res = AST_DEVICE_INUSE;
2461                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2462                                         if (res == AST_DEVICE_INVALID)
2463                                                 res = AST_DEVICE_UNKNOWN;
2464                                 } else if (res == AST_DEVICE_INVALID)   
2465                                         res = AST_DEVICE_UNAVAILABLE;
2466                         }
2467                         if (!strcmp(data, p->agent)) {
2468                                 ast_mutex_unlock(&p->lock);
2469                                 break;
2470                         }
2471                 }
2472                 ast_mutex_unlock(&p->lock);
2473         }
2474         AST_LIST_UNLOCK(&agents);
2475         return res;
2476 }
2477
2478 static struct agent_pvt *find_agent(char *agentid)
2479 {
2480         struct agent_pvt *cur;
2481
2482         AST_LIST_TRAVERSE(&agents, cur, list) {
2483                 if (!strcmp(cur->agent, agentid))
2484                         break;  
2485         }
2486
2487         return cur;     
2488 }
2489
2490 static int function_agent(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
2491 {
2492         char *parse;    
2493         AST_DECLARE_APP_ARGS(args,
2494                 AST_APP_ARG(agentid);
2495                 AST_APP_ARG(item);
2496         );
2497         char *tmp;
2498         struct agent_pvt *agent;
2499
2500         buf[0] = '\0';
2501
2502         if (ast_strlen_zero(data)) {
2503                 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2504                 return -1;
2505         }
2506
2507         parse = ast_strdupa(data);
2508
2509         AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2510         if (!args.item)
2511                 args.item = "status";
2512
2513         if (!(agent = find_agent(args.agentid))) {
2514                 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2515                 return -1;
2516         }
2517
2518         if (!strcasecmp(args.item, "status")) {
2519                 char *status = "LOGGEDOUT";
2520                 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
2521                         status = "LOGGEDIN";    
2522                 ast_copy_string(buf, status, len);
2523         } else if (!strcasecmp(args.item, "password")) 
2524                 ast_copy_string(buf, agent->password, len);
2525         else if (!strcasecmp(args.item, "name"))
2526                 ast_copy_string(buf, agent->name, len);
2527         else if (!strcasecmp(args.item, "mohclass"))
2528                 ast_copy_string(buf, agent->moh, len);
2529         else if (!strcasecmp(args.item, "channel")) {
2530                 if (agent->chan) {
2531                         ast_copy_string(buf, agent->chan->name, len);
2532                         tmp = strrchr(buf, '-');
2533                         if (tmp)
2534                                 *tmp = '\0';
2535                 } 
2536         } else if (!strcasecmp(args.item, "exten"))
2537                 ast_copy_string(buf, agent->loginchan, len);    
2538
2539         return 0;
2540 }
2541
2542 struct ast_custom_function agent_function = {
2543         .name = "AGENT",
2544         .synopsis = "Gets information about an Agent",
2545         .syntax = "AGENT(<agentid>[:item])",
2546         .read = function_agent,
2547         .desc = "The valid items to retrieve are:\n"
2548         "- status (default)      The status of the agent\n"
2549         "                          LOGGEDIN | LOGGEDOUT\n"
2550         "- password              The password of the agent\n"
2551         "- name                  The name of the agent\n"
2552         "- mohclass              MusicOnHold class\n"
2553         "- exten                 The callback extension for the Agent (AgentCallbackLogin)\n"
2554         "- channel               The name of the active channel for the Agent (AgentLogin)\n"
2555 };
2556
2557
2558 /*!
2559  * \brief Initialize the Agents module.
2560  * This function is being called by Asterisk when loading the module. 
2561  * Among other things it registers applications, cli commands and reads the cofiguration file.
2562  *
2563  * \returns int Always 0.
2564  */
2565 static int load_module(void)
2566 {
2567         /* Make sure we can register our agent channel type */
2568         if (ast_channel_register(&agent_tech)) {
2569                 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2570                 return -1;
2571         }
2572         /* Read in the config */
2573         if (!read_agent_config())
2574                 return AST_MODULE_LOAD_DECLINE;
2575         if (persistent_agents)
2576                 reload_agents();
2577         /* Dialplan applications */
2578         ast_register_application(app, login_exec, synopsis, descrip);
2579         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2580         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2581
2582         /* Manager commands */
2583         ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2584         ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2585         ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
2586
2587         /* CLI Commands */
2588         ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2589
2590         /* Dialplan Functions */
2591         ast_custom_function_register(&agent_function);
2592
2593         return 0;
2594 }
2595
2596 static int reload(void)
2597 {
2598         read_agent_config();
2599         if (persistent_agents)
2600                 reload_agents();
2601         return 0;
2602 }
2603
2604 static int unload_module(void)
2605 {
2606         struct agent_pvt *p;
2607         /* First, take us out of the channel loop */
2608         ast_channel_unregister(&agent_tech);
2609         /* Unregister dialplan functions */
2610         ast_custom_function_unregister(&agent_function);        
2611         /* Unregister CLI commands */
2612         ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2613         /* Unregister dialplan applications */
2614         ast_unregister_application(app);
2615         ast_unregister_application(app2);
2616         ast_unregister_application(app3);
2617         /* Unregister manager command */
2618         ast_manager_unregister("Agents");
2619         ast_manager_unregister("AgentLogoff");
2620         ast_manager_unregister("AgentCallbackLogin");
2621         /* Unregister channel */
2622         AST_LIST_LOCK(&agents);
2623         /* Hangup all interfaces if they have an owner */
2624         while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2625                 if (p->owner)
2626                         ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2627                 free(p);
2628         }
2629         AST_LIST_UNLOCK(&agents);
2630         AST_LIST_HEAD_DESTROY(&agents);
2631         return 0;
2632 }
2633
2634 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
2635                 .load = load_module,
2636                 .unload = unload_module,
2637                 .reload = reload,
2638                );