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