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