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