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