39f2cbac252ebdbdc5ed3b763dbc5f22f780581a
[asterisk/asterisk.git] / channels / chan_agent.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of Session Initiation Protocol
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
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 <pthread.h>
16 #include <string.h>
17 #include <asterisk/lock.h>
18 #include <asterisk/channel.h>
19 #include <asterisk/channel_pvt.h>
20 #include <asterisk/config.h>
21 #include <asterisk/logger.h>
22 #include <asterisk/module.h>
23 #include <asterisk/pbx.h>
24 #include <asterisk/options.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/sched.h>
27 #include <asterisk/io.h>
28 #include <asterisk/rtp.h>
29 #include <asterisk/acl.h>
30 #include <asterisk/callerid.h>
31 #include <asterisk/file.h>
32 #include <asterisk/cli.h>
33 #include <asterisk/app.h>
34 #include <asterisk/musiconhold.h>
35 #include <asterisk/manager.h>
36 #include <asterisk/parking.h>
37 #include <sys/socket.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <stdlib.h>
41 #include <fcntl.h>
42 #include <netdb.h>
43 #include <arpa/inet.h>
44 #include <sys/signal.h>
45
46 static char *desc = "Agent Proxy Channel";
47 static char *type = "Agent";
48 static char *tdesc = "Call Agent Proxy Channel";
49 static char *config = "agents.conf";
50
51 static char *app = "AgentLogin";
52 static char *app2 = "AgentCallbackLogin";
53
54 static char *synopsis = "Call agent login";
55 static char *synopsis2 = "Call agent callback login";
56
57 static char *descrip =
58 "  AgentLogin([AgentNo][|options]):\n"
59 "Asks the agent to login to the system.  Always returns -1.  While\n"
60 "logged in, the agent can receive calls and will hear a 'beep'\n"
61 "when a new call comes in.  The agent can dump the call by pressing\n"
62 "the star key.\n"
63 "The option string may contain zero or more of the following characters:\n"
64 "      's' -- silent login - do not announce the login ok segment\n";
65
66 static char *descrip2 =
67 "  AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
68 "Asks the agent to login to the system with callback.  Always returns -1.\n"
69 "The agent's callback extension is called (optionally with the specified\n"
70 "context. \n";
71
72 static char moh[80] = "default";
73
74 #define AST_MAX_AGENT   80              /* Agent ID or Password max length */
75
76 static int capability = -1;
77
78 static unsigned int group;
79 static int autologoff;
80 static int wrapuptime;
81 static int ackcall;
82
83 static int usecnt =0;
84 static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
85
86 /* Protect the interface list (of sip_pvt's) */
87 static ast_mutex_t agentlock = AST_MUTEX_INITIALIZER;
88
89 static struct agent_pvt {
90         ast_mutex_t lock;                               /* Channel private lock */
91         int dead;                                                       /* Poised for destruction? */
92         int pending;                                            /* Not a real agent -- just pending a match */
93         int abouttograb;                                        /* About to grab */
94         int autologoff;                                 /* Auto timeout time */
95         int ackcall;                                    /* ackcall */
96         time_t start;                                           /* When call started */
97         struct timeval lastdisc;                        /* When last disconnected */
98         int wrapuptime;                                         /* Wrapup time in ms */
99         unsigned int group;                                     /* Group memberships */
100         int acknowledged;                                       /* Acknowledged */
101         char moh[80];                                           /* Which music on hold */
102         char agent[AST_MAX_AGENT];                      /* Agent ID */
103         char password[AST_MAX_AGENT];           /* Password for Agent login */
104         char name[AST_MAX_AGENT];
105         ast_mutex_t app_lock;                   /* Synchronization between owning applications */
106         volatile pthread_t owning_app;          /* Owning application thread id */
107         volatile int app_sleep_cond;            /* Sleep condition for the login app */
108         struct ast_channel *owner;                      /* Agent */
109         char loginchan[80];
110         struct ast_channel *chan;                       /* Channel we use */
111         struct agent_pvt *next;                         /* Agent */
112 } *agents = NULL;
113
114 #define CHECK_FORMATS(ast, p) do { \
115         if (p->chan) {\
116                 if (ast->nativeformats != p->chan->nativeformats) { \
117                         ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
118                         /* Native formats changed, reset things */ \
119                         ast->nativeformats = p->chan->nativeformats; \
120                         ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
121                         ast_set_read_format(ast, ast->readformat); \
122                         ast_set_write_format(ast, ast->writeformat); \
123                 } \
124                 if (p->chan->readformat != ast->pvt->rawreadformat)  \
125                         ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
126                 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
127                         ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
128         } \
129 } while(0)
130
131 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
132    properly for a timingfd XXX This might need more work if agents were logged in as agents or other
133    totally impractical combinations XXX */
134
135 #define CLEANUP(ast, p) do { \
136         int x; \
137         if (p->chan) { \
138                 for (x=0;x<AST_MAX_FDS;x++) {\
139                         if (x != AST_MAX_FDS - 2) \
140                                 ast->fds[x] = p->chan->fds[x]; \
141                 } \
142                 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
143         } \
144 } while(0)
145
146
147 static void agent_unlink(struct agent_pvt *agent)
148 {
149         struct agent_pvt *p, *prev;
150         prev = NULL;
151         p = agents;
152         while(p) {
153                 if (p == agent) {
154                         if (prev)
155                                 prev->next = agent->next;
156                         else
157                                 agents = agent->next;
158                         break;
159                 }
160                 prev = p;
161                 p = p->next;
162         }
163 }
164
165 static struct agent_pvt *add_agent(char *agent, int pending)
166 {
167         char tmp[256];
168         char *password=NULL, *name=NULL;
169         struct agent_pvt *p, *prev;
170         
171         strncpy(tmp, agent, sizeof(tmp));
172         if ((password = strchr(tmp, ','))) {
173                 *password = '\0';
174                 password++;
175                 while (*password < 33) password++;
176         }
177         if (password && (name = strchr(password, ','))) {
178                 *name = '\0';
179                 name++;
180                 while (*name < 33) name++; 
181         }
182         prev=NULL;
183         p = agents;
184         while(p) {
185                 if (!pending && !strcmp(p->agent, tmp))
186                         break;
187                 prev = p;
188                 p = p->next;
189         }
190         if (!p) {
191                 p = malloc(sizeof(struct agent_pvt));
192                 if (p) {
193                         memset(p, 0, sizeof(struct agent_pvt));
194                         strncpy(p->agent, tmp, sizeof(p->agent) -1);
195                         ast_mutex_init( &p->lock );
196                         ast_mutex_init( &p->app_lock );
197                         p->owning_app = -1;
198                         p->app_sleep_cond = 1;
199                         p->group = group;
200                         p->pending = pending;
201                         p->next = NULL;
202                         if (prev)
203                                 prev->next = p;
204                         else
205                                 agents = p;
206                         
207                 }
208         }
209         if (!p)
210                 return NULL;
211         strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
212         strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
213         strncpy(p->moh, moh, sizeof(p->moh) - 1);
214         p->ackcall = ackcall;
215         p->autologoff = autologoff;
216         p->wrapuptime = wrapuptime;
217         if (pending)
218                 p->dead = 1;
219         else
220                 p->dead = 0;
221         return p;
222 }
223
224 static int agent_cleanup(struct agent_pvt *p)
225 {
226         struct ast_channel *chan = p->owner;
227         p->owner = NULL;
228         chan->pvt->pvt = NULL;
229         p->app_sleep_cond = 1;
230         /* Release ownership of the agent to other threads (presumably running the login app). */
231         ast_mutex_unlock(&p->app_lock);
232         if (chan)
233                 ast_channel_free(chan);
234         if (p->dead)
235                 free(p);
236         return 0;
237 }
238
239 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
240
241 static int agent_answer(struct ast_channel *ast)
242 {
243         ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
244         return -1;
245 }
246
247 static struct ast_frame  *agent_read(struct ast_channel *ast)
248 {
249         struct agent_pvt *p = ast->pvt->pvt;
250         struct ast_frame *f = NULL;
251         static struct ast_frame null_frame = { AST_FRAME_NULL, };
252         static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
253         ast_mutex_lock(&p->lock); 
254         CHECK_FORMATS(ast, p);
255         if (p->chan) {
256                 p->chan->exception = ast->exception;
257                 if (ast->fdno == AST_MAX_FDS - 3)
258                         p->chan->fdno = AST_MAX_FDS - 2;
259                 else
260                         p->chan->fdno = ast->fdno;
261                 f = ast_read(p->chan);
262         } else
263                 f = &null_frame;
264         if (!f) {
265                 /* If there's a channel, hang it up  (if it's on a callback) make it NULL */
266                 if (p->chan) {
267                         if (strlen(p->loginchan))
268                                 ast_hangup(p->chan);
269                         p->chan = NULL;
270                         p->acknowledged = 0;
271                 }
272         }
273         if (f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
274 /* TC */
275                 if (p->ackcall) {
276                         if (option_verbose > 2)
277                                 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
278                         /* Don't pass answer along */
279                         ast_frfree(f);
280                         f = &null_frame;
281                 }
282         else {
283                         p->acknowledged = 1;
284                         f = &answer_frame;
285         }
286         }
287         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
288                 if (!p->acknowledged) {
289                         if (option_verbose > 2)
290                                 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
291                         p->acknowledged = 1;
292                         ast_frfree(f);
293                         f = &answer_frame;
294                 }
295         }
296         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
297                 /* * terminates call */
298                 ast_frfree(f);
299                 f = NULL;
300         }
301         CLEANUP(ast,p);
302         ast_mutex_unlock(&p->lock);
303         return f;
304 }
305
306 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
307 {
308         struct agent_pvt *p = ast->pvt->pvt;
309         int res = -1;
310         CHECK_FORMATS(ast, p);
311         ast_mutex_lock(&p->lock);
312         if (p->chan) {
313                 if ((f->frametype != AST_FRAME_VOICE) ||
314                         (f->subclass == p->chan->writeformat)) {
315                         res = ast_write(p->chan, f);
316                 } else {
317                         ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
318                         res = 0;
319                 }
320         } else
321                 res = 0;
322         CLEANUP(ast, p);
323         ast_mutex_unlock(&p->lock);
324         return res;
325 }
326
327 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
328 {
329         struct agent_pvt *p = newchan->pvt->pvt;
330         ast_mutex_lock(&p->lock);
331         if (p->owner != oldchan) {
332                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
333                 ast_mutex_unlock(&p->lock);
334                 return -1;
335         }
336         p->owner = newchan;
337         ast_mutex_unlock(&p->lock);
338         return 0;
339 }
340
341 static int agent_indicate(struct ast_channel *ast, int condition)
342 {
343         struct agent_pvt *p = ast->pvt->pvt;
344         int res = -1;
345         ast_mutex_lock(&p->lock);
346         if (p->chan)
347                 res = ast_indicate(p->chan, condition);
348         else
349                 res = 0;
350         ast_mutex_unlock(&p->lock);
351         return res;
352 }
353
354 static int agent_digit(struct ast_channel *ast, char digit)
355 {
356         struct agent_pvt *p = ast->pvt->pvt;
357         int res = -1;
358         ast_mutex_lock(&p->lock);
359         if (p->chan)
360                 res = p->chan->pvt->send_digit(p->chan, digit);
361         else
362                 res = 0;
363         ast_mutex_unlock(&p->lock);
364         return res;
365 }
366
367 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
368 {
369         struct agent_pvt *p = ast->pvt->pvt;
370         int res = -1;
371         ast_mutex_lock(&p->lock);
372         p->acknowledged = 0;
373         if (!p->chan) {
374                 if (p->pending) {
375                         ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
376                         ast_setstate(ast, AST_STATE_DIALING);
377                         res = 0;
378                 } else {
379                         ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
380                         res = -1;
381                 }
382                 ast_mutex_unlock(&p->lock);
383                 return res;
384         } else if (strlen(p->loginchan)) {
385                 time(&p->start);
386                 /* Call on this agent */
387                 if (option_verbose > 2)
388                         ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
389                 if (p->chan->callerid)
390                         free(p->chan->callerid);
391                 if (ast->callerid)
392                         p->chan->callerid = strdup(ast->callerid);
393                 else
394                         p->chan->callerid = NULL;
395                 res = ast_call(p->chan, p->loginchan, 0);
396                 CLEANUP(ast,p);
397                 ast_mutex_unlock(&p->lock);
398                 return res;
399         }
400         ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
401         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
402         res = ast_streamfile(p->chan, "beep", p->chan->language);
403         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
404         if (!res) {
405                 res = ast_waitstream(p->chan, "");
406                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
407         }
408         if (!res) {
409                 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
410                 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
411                 if (res)
412                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
413         } else {
414                 // Agent hung-up
415                 p->chan = NULL;
416         }
417
418         if (!res) {
419                 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
420                 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
421                 if (res)
422                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
423         }
424         if( !res )
425         {
426                 /* Call is immediately up, or might need ack */
427                 if (p->ackcall > 1)
428                         ast_setstate(ast, AST_STATE_RINGING);
429                 else {
430                         ast_setstate(ast, AST_STATE_UP);
431                         p->acknowledged = 1;
432                 }
433                 res = 0;
434         }
435         CLEANUP(ast,p);
436         ast_mutex_unlock(&p->lock);
437         return res;
438 }
439
440 static int agent_hangup(struct ast_channel *ast)
441 {
442         struct agent_pvt *p = ast->pvt->pvt;
443         int howlong = 0;
444         ast_mutex_lock(&p->lock);
445         p->owner = NULL;
446         ast->pvt->pvt = NULL;
447         p->app_sleep_cond = 1;
448         p->acknowledged = 0;
449         if (p->start && (ast->_state != AST_STATE_UP))
450                 howlong = time(NULL) - p->start;
451         time(&p->start);
452         if (p->chan) {
453                 /* If they're dead, go ahead and hang up on the agent now */
454                 if (strlen(p->loginchan)) {
455                         if (p->chan) {
456                                 /* Recognize the hangup and pass it along immediately */
457                                 ast_hangup(p->chan);
458                                 p->chan = NULL;
459                         }
460                         ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
461                         if (howlong  && p->autologoff && (howlong > p->autologoff)) {
462                                 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
463                                 strcpy(p->loginchan, "");
464                         }
465                 } else if (p->dead) {
466                         ast_mutex_lock(&p->chan->lock);
467                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
468                         ast_mutex_unlock(&p->chan->lock);
469                 } else {
470                         ast_mutex_lock(&p->chan->lock);
471                         ast_moh_start(p->chan, p->moh);
472                         ast_mutex_unlock(&p->chan->lock);
473                 }
474         }
475 #if 0
476                 ast_mutex_unlock(&p->lock);
477                 /* Release ownership of the agent to other threads (presumably running the login app). */
478                 ast_mutex_unlock(&p->app_lock);
479         } else if (p->dead) {
480                 /* Go ahead and lose it */
481                 ast_mutex_unlock(&p->lock);
482                 /* Release ownership of the agent to other threads (presumably running the login app). */
483                 ast_mutex_unlock(&p->app_lock);
484         } else {
485                 ast_mutex_unlock(&p->lock);
486                 /* Release ownership of the agent to other threads (presumably running the login app). */
487                 ast_mutex_unlock(&p->app_lock);
488         }
489 #endif  
490         ast_mutex_unlock(&p->lock);
491
492         if (p->pending) {
493                 ast_mutex_lock(&agentlock);
494                 agent_unlink(p);
495                 ast_mutex_unlock(&agentlock);
496         }
497         if (p->abouttograb) {
498                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
499                    kill it later */
500                 p->abouttograb = 0;
501         } else if (p->dead) {
502                 free(p);
503         } else if (p->chan) {
504                 /* Not dead -- check availability now */
505                 ast_mutex_lock(&p->lock);
506                 /* Store last disconnect time */
507                 gettimeofday(&p->lastdisc, NULL);
508                 ast_mutex_unlock(&p->lock);
509                 /* Release ownership of the agent to other threads (presumably running the login app). */
510                 ast_mutex_unlock(&p->app_lock);
511         }
512         return 0;
513 }
514
515 static int agent_cont_sleep( void *data )
516 {
517         struct agent_pvt *p;
518         struct timeval tv;
519         int res;
520
521         p = (struct agent_pvt *)data;
522
523         ast_mutex_lock(&p->lock);
524         res = p->app_sleep_cond;
525         if (p->lastdisc.tv_sec) {
526                 gettimeofday(&tv, NULL);
527                 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
528                         (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) 
529                         res = 1;
530         }
531         ast_mutex_unlock(&p->lock);
532 #if 0
533         if( !res )
534                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
535 #endif          
536         return res;
537 }
538
539 static int agent_ack_sleep( void *data )
540 {
541         struct agent_pvt *p;
542         int res=0;
543         int to = 1000;
544
545         /* Wait a second and look for something */
546
547         p = (struct agent_pvt *)data;
548         if (p->chan) {
549                 for(;;) {
550                         to = ast_waitfor(p->chan, to);
551                         if (to < 0) {
552                                 res = -1;
553                                 break;
554                         }
555                         if (!to) {
556                                 res = 0;
557                                 break;
558                         }
559                         ast_mutex_lock(&p->lock);
560                         if (!p->app_sleep_cond) {
561                                 ast_mutex_unlock(&p->lock);
562                                 res = 0;
563                                 break;
564                         } else if (res == '#') {
565                                 ast_mutex_unlock(&p->lock);
566                                 res = 1;
567                                 break;
568                         }
569                         ast_mutex_unlock(&p->lock);
570                         res = 0;
571                 }
572         } else
573                 res = -1;
574         return res;
575 }
576
577 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
578 {
579         struct ast_channel *tmp;
580         struct ast_frame null_frame = { AST_FRAME_NULL };
581 #if 0
582         if (!p->chan) {
583                 ast_log(LOG_WARNING, "No channel? :(\n");
584                 return NULL;
585         }
586 #endif  
587         tmp = ast_channel_alloc(0);
588         if (tmp) {
589                 if (p->chan) {
590                         tmp->nativeformats = p->chan->nativeformats;
591                         tmp->writeformat = p->chan->writeformat;
592                         tmp->pvt->rawwriteformat = p->chan->writeformat;
593                         tmp->readformat = p->chan->readformat;
594                         tmp->pvt->rawreadformat = p->chan->readformat;
595                         strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
596                         strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
597                         strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
598                 } else {
599                         tmp->nativeformats = AST_FORMAT_SLINEAR;
600                         tmp->writeformat = AST_FORMAT_SLINEAR;
601                         tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
602                         tmp->readformat = AST_FORMAT_SLINEAR;
603                         tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
604                 }
605                 if (p->pending)
606                         snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
607                 else
608                         snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
609                 tmp->type = type;
610                 ast_setstate(tmp, state);
611                 tmp->pvt->pvt = p;
612                 tmp->pvt->send_digit = agent_digit;
613                 tmp->pvt->call = agent_call;
614                 tmp->pvt->hangup = agent_hangup;
615                 tmp->pvt->answer = agent_answer;
616                 tmp->pvt->read = agent_read;
617                 tmp->pvt->write = agent_write;
618                 tmp->pvt->exception = agent_read;
619                 tmp->pvt->indicate = agent_indicate;
620                 tmp->pvt->fixup = agent_fixup;
621                 p->owner = tmp;
622                 ast_mutex_lock(&usecnt_lock);
623                 usecnt++;
624                 ast_mutex_unlock(&usecnt_lock);
625                 ast_update_use_count();
626                 tmp->priority = 1;
627                 /* Wake up and wait for other applications (by definition the login app)
628                  * to release this channel). Takes ownership of the agent channel
629                  * to this thread only.
630                  * For signalling the other thread, ast_queue_frame is used until we
631                  * can safely use signals for this purpose. The pselect() needs to be
632                  * implemented in the kernel for this.
633                  */
634                 p->app_sleep_cond = 0;
635                 if( ast_mutex_trylock(&p->app_lock) )
636                 {
637                         if (p->chan) {
638                                 ast_queue_frame(p->chan, &null_frame, 1);
639                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
640                                 ast_mutex_lock(&p->app_lock);
641                                 ast_mutex_lock(&p->lock);
642                         }
643                         if( !p->chan )
644                         {
645                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
646                                 p->owner = NULL;
647                                 tmp->pvt->pvt = NULL;
648                                 p->app_sleep_cond = 1;
649                                 ast_channel_free( tmp );
650                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
651                                 ast_mutex_unlock(&p->app_lock);
652                                 return NULL;
653                         }
654                 }
655                 p->owning_app = pthread_self();
656                 /* After the above step, there should not be any blockers. */
657                 if (p->chan) {
658                         if (p->chan->blocking) {
659                                 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
660                                 CRASH;
661                         }
662                         ast_moh_stop(p->chan);
663                 }
664         } else
665                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
666         return tmp;
667 }
668
669
670 static int read_agent_config(void)
671 {
672         struct ast_config *cfg;
673         struct ast_variable *v;
674         struct agent_pvt *p, *pl, *pn;
675         group = 0;
676         autologoff = 0;
677         wrapuptime = 0;
678         ackcall = 1;
679         cfg = ast_load(config);
680         if (!cfg) {
681                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
682                 return 0;
683         }
684         ast_mutex_lock(&agentlock);
685         p = agents;
686         while(p) {
687                 p->dead = 1;
688                 p = p->next;
689         }
690         strcpy(moh, "default");
691         v = ast_variable_browse(cfg, "agents");
692         while(v) {
693                 /* Create the interface list */
694                 if (!strcasecmp(v->name, "agent")) {
695                         add_agent(v->value, 0);
696                 } else if (!strcasecmp(v->name, "group")) {
697                         group = ast_get_group(v->value);
698                 } else if (!strcasecmp(v->name, "autologoff")) {
699                         autologoff = atoi(v->value);
700                         if (autologoff < 0)
701                                 autologoff = 0;
702                 } else if (!strcasecmp(v->name, "ackcall")) {
703                         if (!strcasecmp(v->value, "always"))
704                                 ackcall = 2;
705                         else if (ast_true(v->value))
706                 ackcall = 1;
707                         else
708                                 ackcall = 0;
709                 } else if (!strcasecmp(v->name, "wrapuptime")) {
710                         wrapuptime = atoi(v->value);
711                         if (wrapuptime < 0)
712                                 wrapuptime = 0;
713                 } else if (!strcasecmp(v->name, "musiconhold")) {
714                         strncpy(moh, v->value, sizeof(moh) - 1);
715                 }
716                 v = v->next;
717         }
718         p = agents;
719         pl = NULL;
720         while(p) {
721                 pn = p->next;
722                 if (p->dead) {
723                         /* Unlink */
724                         if (pl)
725                                 pl->next = p->next;
726                         else
727                                 agents = p->next;
728                         /* Destroy if  appropriate */
729                         if (!p->owner) {
730                                 if (!p->chan) {
731                                         free(p);
732                                 } else {
733                                         /* Cause them to hang up */
734                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
735                                 }
736                         }
737                 } else
738                         pl = p;
739                 p = pn;
740         }
741         ast_mutex_unlock(&agentlock);
742         ast_destroy(cfg);
743         return 0;
744 }
745
746 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
747 {
748         struct ast_channel *chan=NULL, *parent=NULL;
749         struct agent_pvt *p;
750         int res;
751         ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
752         if (needlock)
753                 ast_mutex_lock(&agentlock);
754         p = agents;
755         while(p) {
756                 if (p == newlyavailable) {
757                         p = p->next;
758                         continue;
759                 }
760                 ast_mutex_lock(&p->lock);
761                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
762                         ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
763                         /* We found a pending call, time to merge */
764                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
765                         parent = p->owner;
766                         p->abouttograb = 1;
767                         ast_mutex_unlock(&p->lock);
768                         break;
769                 }
770                 ast_mutex_unlock(&p->lock);
771                 p = p->next;
772         }
773         if (needlock)
774                 ast_mutex_unlock(&agentlock);
775         if (parent && chan)  {
776                 if (p->ackcall > 1) {
777                         /* Don't do beep here */
778                         res = 0;
779                 } else {
780                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
781                         res = ast_streamfile(newlyavailable->chan, "beep", newlyavailable->chan->language);
782                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
783                         if (!res) {
784                                 res = ast_waitstream(newlyavailable->chan, "");
785                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
786                         }
787                 }
788                 if (!res) {
789                         /* Note -- parent may have disappeared */
790                         if (p->abouttograb) {
791                                 ast_setstate(parent, AST_STATE_UP);
792                                 ast_setstate(chan, AST_STATE_UP);
793                                 /* Go ahead and mark the channel as a zombie so that masquerade will
794                                    destroy it for us, and we need not call ast_hangup */
795                                 ast_mutex_lock(&parent->lock);
796                                 chan->zombie = 1;
797                                 ast_channel_masquerade(parent, chan);
798                                 ast_mutex_unlock(&parent->lock);
799                                 p->abouttograb = 0;
800                         } else {
801                                 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
802                                 agent_cleanup(newlyavailable);
803                         }
804                 } else {
805                         ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
806                         agent_cleanup(newlyavailable);
807                 }
808         }
809         return 0;
810 }
811
812 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
813 {
814         struct agent_pvt *p;
815         int res=0;
816         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
817         if (needlock)
818                 ast_mutex_lock(&agentlock);
819         p = agents;
820         while(p) {
821                 if (p == newlyavailable) {
822                         p = p->next;
823                         continue;
824                 }
825                 ast_mutex_lock(&p->lock);
826                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
827                         ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
828                         ast_mutex_unlock(&p->lock);
829                         break;
830                 }
831                 ast_mutex_unlock(&p->lock);
832                 p = p->next;
833         }
834         if (needlock)
835                 ast_mutex_unlock(&agentlock);
836         if (p) {
837                 ast_mutex_unlock(&newlyavailable->lock);
838                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
839                 res = ast_streamfile(newlyavailable->chan, "beep", newlyavailable->chan->language);
840                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
841                 if (!res) {
842                         res = ast_waitstream(newlyavailable->chan, "");
843                         ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
844                 }
845                 ast_mutex_lock(&newlyavailable->lock);
846         }
847         return res;
848 }
849
850 static struct ast_channel *agent_request(char *type, int format, void *data)
851 {
852         struct agent_pvt *p;
853         struct ast_channel *chan = NULL;
854         char *s;
855         unsigned int groupmatch;
856         int waitforagent=0;
857         int hasagent = 0;
858         s = data;
859         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
860                 groupmatch = (1 << groupmatch);
861         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
862                 groupmatch = (1 << groupmatch);
863                 waitforagent = 1;
864         } else {
865                 groupmatch = 0;
866         }
867
868         /* Check actual logged in agents first */
869         ast_mutex_lock(&agentlock);
870         p = agents;
871         while(p) {
872                 ast_mutex_lock(&p->lock);
873                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
874                                 !strlen(p->loginchan)) {
875                         if (p->chan)
876                                 hasagent++;
877                         if (!p->lastdisc.tv_sec) {
878                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
879                                 if (!p->owner && p->chan) {
880                                         /* Fixed agent */
881                                         chan = agent_new(p, AST_STATE_DOWN);
882                                 }
883                                 if (chan) {
884                                         ast_mutex_unlock(&p->lock);
885                                         break;
886                                 }
887                         }
888                 }
889                 ast_mutex_unlock(&p->lock);
890                 p = p->next;
891         }
892         if (!p) {
893                 p = agents;
894                 while(p) {
895                         ast_mutex_lock(&p->lock);
896                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
897                                 if (p->chan || strlen(p->loginchan))
898                                         hasagent++;
899                                 if (!p->lastdisc.tv_sec) {
900                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
901                                         if (!p->owner && p->chan) {
902                                                 /* Could still get a fixed agent */
903                                                 chan = agent_new(p, AST_STATE_DOWN);
904                                         } else if (!p->owner && strlen(p->loginchan)) {
905                                                 /* Adjustable agent */
906                                                 p->chan = ast_request("Local", format, p->loginchan);
907                                                 if (p->chan)
908                                                         chan = agent_new(p, AST_STATE_DOWN);
909                                         }
910                                         if (chan) {
911                                                 ast_mutex_unlock(&p->lock);
912                                                 break;
913                                         }
914                                 }
915                         }
916                         ast_mutex_unlock(&p->lock);
917                         p = p->next;
918                 }
919         }
920
921         if (!chan && waitforagent) {
922                 /* No agent available -- but we're requesting to wait for one.
923                    Allocate a place holder */
924                 if (hasagent) {
925                         ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
926                         p = add_agent(data, 1);
927                         p->group = groupmatch;
928                         chan = agent_new(p, AST_STATE_DOWN);
929                         if (!chan) {
930                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
931                         }
932                 } else
933                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
934         }
935         ast_mutex_unlock(&agentlock);
936         return chan;
937 }
938
939 static int powerof(unsigned int v)
940 {
941         int x;
942         for (x=0;x<32;x++) {
943                 if (v & (1 << x)) return x;
944         }
945         return 0;
946 }
947
948 static int agents_show(int fd, int argc, char **argv)
949 {
950         struct agent_pvt *p;
951         char username[256];
952         char location[256];
953         char talkingto[256];
954         char moh[256];
955
956         if (argc != 2)
957                 return RESULT_SHOWUSAGE;
958         ast_mutex_lock(&agentlock);
959         p = agents;
960         while(p) {
961                 ast_mutex_lock(&p->lock);
962                 if (p->pending) {
963                         if (p->group)
964                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
965                         else
966                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
967                 } else {
968                         if (strlen(p->name))
969                                 snprintf(username, sizeof(username), "(%s) ", p->name);
970                         else
971                                 strcpy(username, "");
972                         if (p->chan) {
973                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
974                                 if (p->owner && p->owner->bridge) {
975                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
976                                 } else {
977                                         strcpy(talkingto, " is idle");
978                                 }
979                         } else if (strlen(p->loginchan)) {
980                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
981                                 strcpy(talkingto, "");
982                                 if (p->acknowledged)
983                                         strcat(location, " (Confirmed)");
984                         } else {
985                                 strcpy(location, "not logged in");
986                                 strcpy(talkingto, "");
987                         }
988                         if (strlen(p->moh))
989                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
990                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
991                                         username, location, talkingto, moh);
992                 }
993                 ast_mutex_unlock(&p->lock);
994                 p = p->next;
995         }
996         ast_mutex_unlock(&agentlock);
997         return RESULT_SUCCESS;
998 }
999
1000 static char show_agents_usage[] = 
1001 "Usage: show agents\n"
1002 "       Provides summary information on agents.\n";
1003
1004 static struct ast_cli_entry cli_show_agents = {
1005         { "show", "agents", NULL }, agents_show, 
1006         "Show status of agents", show_agents_usage, NULL };
1007
1008 STANDARD_LOCAL_USER;
1009 LOCAL_USER_DECL;
1010
1011 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1012 {
1013         int res=0;
1014         int tries = 0;
1015         struct agent_pvt *p;
1016         struct localuser *u;
1017         struct timeval tv;
1018         char user[AST_MAX_AGENT];
1019         char pass[AST_MAX_AGENT];
1020         char xpass[AST_MAX_AGENT] = "";
1021         char *errmsg;
1022         char info[512];
1023         char *opt_user = NULL;
1024         char *options = NULL;
1025         char *context = NULL;
1026         char *exten = NULL;
1027         int play_announcement;
1028         char *filename = "agent-loginok";
1029         
1030         LOCAL_USER_ADD(u);
1031
1032         /* Parse the arguments XXX Check for failure XXX */
1033         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1034         opt_user = info;
1035         if( opt_user ) {
1036                 options = strchr(opt_user, '|');
1037                 if (options) {
1038                         *options = '\0';
1039                         options++;
1040                         if (callbackmode) {
1041                                 context = strchr(options, '@');
1042                                 if (context) {
1043                                         *context = '\0';
1044                                         context++;
1045                                 }
1046                                 exten = options;
1047                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1048                                 if (!*exten)
1049                                         exten = NULL;
1050                         }
1051                 }
1052         }
1053
1054         if (chan->_state != AST_STATE_UP)
1055                 res = ast_answer(chan);
1056         if (!res) {
1057                 if( opt_user && strlen(opt_user))
1058                         strncpy( user, opt_user, AST_MAX_AGENT );
1059                 else
1060                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1061         }
1062         while (!res && (tries < 3)) {
1063                 /* Check for password */
1064                 ast_mutex_lock(&agentlock);
1065                 p = agents;
1066                 while(p) {
1067                         if (!strcmp(p->agent, user) && !p->pending)
1068                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1069                         p = p->next;
1070                 }
1071                 ast_mutex_unlock(&agentlock);
1072                 if (!res) {
1073                         if (strlen(xpass))
1074                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1075                         else
1076                                 strcpy(pass, "");
1077                 }
1078                 errmsg = "agent-incorrect";
1079
1080 #if 0
1081                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1082 #endif          
1083
1084                 /* Check again for accuracy */
1085                 ast_mutex_lock(&agentlock);
1086                 p = agents;
1087                 while(p) {
1088                         ast_mutex_lock(&p->lock);
1089                         if (!strcmp(p->agent, user) &&
1090                                 !strcmp(p->password, pass) && !p->pending) {
1091                                         if (!p->chan) {
1092                                                 if (callbackmode) {
1093                                                         char tmpchan[256] = "";
1094                                                         int pos = 0;
1095                                                         /* Retrieve login chan */
1096                                                         for (;;) {
1097                                                                 if (exten) {
1098                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1099                                                                         res = 0;
1100                                                                 } else
1101                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1102                                                                 if (!strlen(tmpchan) || ast_exists_extension(chan, context && strlen(context) ? context : "default", tmpchan,
1103                                                                                         1, NULL))
1104                                                                         break;
1105                                                                 if (exten) {
1106                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1107                                                                         exten = NULL;
1108                                                                         pos = 0;
1109                                                                 } else {
1110                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1111                                                                         if (!res)
1112                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1113                                                                         if (res > 0) {
1114                                                                                 tmpchan[0] = res;
1115                                                                                 tmpchan[1] = '\0';
1116                                                                                 pos = 1;
1117                                                                         } else {
1118                                                                                 tmpchan[0] = '\0';
1119                                                                                 pos = 0;
1120                                                                         }
1121                                                                 }
1122                                                         }
1123                                                         if (!res) {
1124                                                                 if (context && strlen(context) && strlen(tmpchan))
1125                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1126                                                                 else
1127                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1128                                                                 if (!strlen(p->loginchan))
1129                                                                         filename = "agent-loggedoff";
1130                                                                 p->acknowledged = 0;
1131                                                         }
1132                                                 } else {
1133                                                         strcpy(p->loginchan, "");
1134                                                         p->acknowledged = 0;
1135                                                 }
1136                                                 play_announcement = 1;
1137                                                 if( options )
1138                                                         if( strchr( options, 's' ) )
1139                                                                 play_announcement = 0;
1140                                                 if( !res && play_announcement )
1141                                                         res = ast_streamfile(chan, filename, chan->language);
1142                                                 if (!res)
1143                                                         ast_waitstream(chan, "");
1144                                                 if (!res) {
1145                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1146                                                         if (res)
1147                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1148                                                 }
1149                                                 if (!res) {
1150                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1151                                                         if (res)
1152                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1153                                                 }
1154                                                 /* Check once more just in case */
1155                                                 if (p->chan)
1156                                                         res = -1;
1157                                                 if (callbackmode && !res) {
1158                                                         /* Just say goodbye and be done with it */
1159                                                         if (!res)
1160                                                                 res = ast_safe_sleep(chan, 500);
1161                                                         res = ast_streamfile(chan, "vm-goodbye", chan->language);
1162                                                         if (!res)
1163                                                                 res = ast_waitstream(chan, "");
1164                                                         if (!res)
1165                                                                 res = ast_safe_sleep(chan, 1000);
1166                                                         ast_mutex_unlock(&p->lock);
1167                                                         ast_mutex_unlock(&agentlock);
1168                                                 } else if (!res) {
1169 #ifdef HONOR_MUSIC_CLASS
1170                                                         /* check if the moh class was changed with setmusiconhold */
1171                                                         if (*(chan->musicclass))
1172                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1173 #endif                                                          
1174                                                         ast_moh_start(chan, p->moh);
1175                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1176                                                                 "Agent: %s\r\n"
1177                                                                 "Channel: %s\r\n",
1178                                                                 p->agent, chan->name);
1179                                                         if (option_verbose > 2)
1180                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1181                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1182                                                         /* Login this channel and wait for it to
1183                                                            go away */
1184                                                         p->chan = chan;
1185                                                         if (p->ackcall > 1)
1186                                                                 check_beep(p, 0);
1187                                                         else
1188                                                                 check_availability(p, 0);
1189                                                         ast_mutex_unlock(&p->lock);
1190                                                         ast_mutex_unlock(&agentlock);
1191                                                         while (res >= 0) {
1192                                                                 ast_mutex_lock(&p->lock);
1193                                                                 if (p->chan != chan)
1194                                                                         res = -1;
1195                                                                 ast_mutex_unlock(&p->lock);
1196                                                                 /* Yield here so other interested threads can kick in. */
1197                                                                 sched_yield();
1198                                                                 if (res)
1199                                                                         break;
1200
1201                                                                 ast_mutex_lock(&p->lock);
1202                                                                 if (p->lastdisc.tv_sec) {
1203                                                                         gettimeofday(&tv, NULL);
1204                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1205                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1206                                                                                         ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1207                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1208                                                                                 if (p->ackcall > 1)
1209                                                                                         check_beep(p, 0);
1210                                                                                 else
1211                                                                                         check_availability(p, 0);
1212                                                                         }
1213                                                                 }
1214                                                                 ast_mutex_unlock(&p->lock);
1215                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1216                                                                 ast_mutex_lock( &p->app_lock );
1217                                                                 ast_mutex_lock(&p->lock);
1218                                                                 p->owning_app = pthread_self();
1219                                                                 ast_mutex_unlock(&p->lock);
1220                                                                 if (p->ackcall > 1) 
1221                                                                         res = agent_ack_sleep(p);
1222                                                                 else
1223                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1224                                                                                                         agent_cont_sleep, p );
1225                                                                 ast_mutex_unlock( &p->app_lock );
1226                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1227                                                                         ast_mutex_lock(&p->lock);
1228                                                                         check_availability(p, 0);
1229                                                                         ast_mutex_unlock(&p->lock);
1230                                                                 }
1231                                                                 sched_yield();
1232                                                         }
1233                                                         ast_mutex_lock(&p->lock);
1234                                                         if (res && p->owner) 
1235                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1236                                                         /* Log us off if appropriate */
1237                                                         if (p->chan == chan)
1238                                                                 p->chan = NULL;
1239                                                         p->acknowledged = 0;
1240                                                         ast_mutex_unlock(&p->lock);
1241                                                         if (option_verbose > 2)
1242                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1243                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1244                                                                 "Agent: %s\r\n",
1245                                                                 p->agent);
1246                                                         /* If there is no owner, go ahead and kill it now */
1247                                                         if (p->dead && !p->owner)
1248                                                                 free(p);
1249                                                 }
1250                                                 else {
1251                                                         ast_mutex_unlock(&p->lock);
1252                                                         p = NULL;
1253                                                 }
1254                                                 res = -1;
1255                                         } else {
1256                                                 ast_mutex_unlock(&p->lock);
1257                                                 errmsg = "agent-alreadyon";
1258                                                 p = NULL;
1259                                         }
1260                                         break;
1261                         }
1262                         ast_mutex_unlock(&p->lock);
1263                         p = p->next;
1264                 }
1265                 if (!p)
1266                         ast_mutex_unlock(&agentlock);
1267
1268                 if (!res)
1269                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1270         }
1271                 
1272         LOCAL_USER_REMOVE(u);
1273         /* Always hangup */
1274         return -1;
1275 }
1276
1277 static int login_exec(struct ast_channel *chan, void *data)
1278 {
1279         return __login_exec(chan, data, 0);
1280 }
1281
1282 static int callback_exec(struct ast_channel *chan, void *data)
1283 {
1284         return __login_exec(chan, data, 1);
1285 }
1286
1287 int load_module()
1288 {
1289         /* Make sure we can register our sip channel type */
1290         if (ast_channel_register(type, tdesc, capability, agent_request)) {
1291                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1292                 return -1;
1293         }
1294         ast_register_application(app, login_exec, synopsis, descrip);
1295         ast_register_application(app2, callback_exec, synopsis2, descrip2);
1296         ast_cli_register(&cli_show_agents);
1297         /* Read in the config */
1298         read_agent_config();
1299         return 0;
1300 }
1301
1302 int reload()
1303 {
1304         read_agent_config();
1305         return 0;
1306 }
1307
1308 int unload_module()
1309 {
1310         struct agent_pvt *p;
1311         /* First, take us out of the channel loop */
1312         ast_cli_unregister(&cli_show_agents);
1313         ast_unregister_application(app);
1314         ast_unregister_application(app2);
1315         ast_channel_unregister(type);
1316         if (!ast_mutex_lock(&agentlock)) {
1317                 /* Hangup all interfaces if they have an owner */
1318                 p = agents;
1319                 while(p) {
1320                         if (p->owner)
1321                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1322                         p = p->next;
1323                 }
1324                 agents = NULL;
1325                 ast_mutex_unlock(&agentlock);
1326         } else {
1327                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1328                 return -1;
1329         }               
1330         return 0;
1331 }
1332
1333 int usecount()
1334 {
1335         int res;
1336         ast_mutex_lock(&usecnt_lock);
1337         res = usecnt;
1338         ast_mutex_unlock(&usecnt_lock);
1339         return res;
1340 }
1341
1342 char *key()
1343 {
1344         return ASTERISK_GPL_KEY;
1345 }
1346
1347 char *description()
1348 {
1349         return desc;
1350 }
1351