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