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