Check if the musiconholdclass was changed with setmusiconhold and if yes then play...
[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 <sys/socket.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdlib.h>
40 #include <fcntl.h>
41 #include <netdb.h>
42 #include <arpa/inet.h>
43 #include <sys/signal.h>
44
45 static char *desc = "Agent Proxy Channel";
46 static char *type = "Agent";
47 static char *tdesc = "Call Agent Proxy Channel";
48 static char *config = "agents.conf";
49
50 static char *app = "AgentLogin";
51
52 static char *synopsis = "Call agent login";
53
54 static char *descrip =
55 "  AgentLogin([AgentNo][|options]):\n"
56 "Asks the agent to login to the system.  Always returns -1.  While\n"
57 "logged in, the agent can receive calls and will hear a 'beep'\n"
58 "when a new call comes in.  The agent can dump the call by pressing\n"
59 "the star key.\n"
60 "The option string may contain zero or more of the following characters:\n"
61 "      's' -- silent login - do not announce the login ok segment\n";
62
63 static char moh[80] = "default";
64
65 #define AST_MAX_AGENT   80              /* Agent ID or Password max length */
66
67 static int capability = -1;
68
69 static int usecnt =0;
70 static pthread_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
71
72 /* Protect the interface list (of sip_pvt's) */
73 static pthread_mutex_t agentlock = AST_MUTEX_INITIALIZER;
74
75 static struct agent_pvt {
76         pthread_mutex_t lock;                           /* Channel private lock */
77         int dead;                                                       /* Poised for destruction? */
78         char moh[80];                                           /* Which music on hold */
79         char agent[AST_MAX_AGENT];                      /* Agent ID */
80         char password[AST_MAX_AGENT];           /* Password for Agent login */
81         char name[AST_MAX_AGENT];
82         pthread_mutex_t app_lock;                       /* Synchronization between owning applications */
83         volatile pthread_t owning_app;          /* Owning application thread id */
84         volatile int app_sleep_cond;            /* Sleep condition for the login app */
85         struct ast_channel *owner;                      /* Agent */
86         struct ast_channel *chan;                       /* Channel we use */
87         struct agent_pvt *next;                         /* Agent */
88 } *agents = NULL;
89
90 #define CLEANUP(ast, p) do { \
91         int x; \
92         if (p->chan) { \
93                 for (x=0;x<AST_MAX_FDS;x++) \
94                         ast->fds[x] = p->chan->fds[x]; \
95         } \
96 } while(0)
97
98
99 static int add_agent(struct ast_variable *var)
100 {
101         char tmp[256];
102         char *password=NULL, *name=NULL;
103         struct agent_pvt *p;
104         
105         strncpy(tmp, var->value, sizeof(tmp));
106         if ((password = strchr(tmp, ','))) {
107                 *password = '\0';
108                 password++;
109                 while (*password < 33) password++;
110         }
111         if (password && (name = strchr(password, ','))) {
112                 *name = '\0';
113                 name++;
114                 while (*name < 33) name++; 
115         }
116         p = agents;
117         while(p) {
118                 if (!strcmp(p->agent, tmp))
119                         break;
120                 p = p->next;
121         }
122         if (!p) {
123                 p = malloc(sizeof(struct agent_pvt));
124                 if (p) {
125                         memset(p, 0, sizeof(struct agent_pvt));
126                         strncpy(p->agent, tmp, sizeof(p->agent) -1);
127                         ast_pthread_mutex_init( &p->lock );
128                         ast_pthread_mutex_init( &p->app_lock );
129                         p->owning_app = -1;
130                         p->app_sleep_cond = 1;
131                         p->next = agents;
132                         agents = p;
133                         
134                 }
135         }
136         if (!p)
137                 return -1;
138         strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
139         strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
140         strncpy(p->moh, moh, sizeof(p->moh) - 1);
141         p->dead = 0;
142         return 0;
143 }
144
145 static int agent_answer(struct ast_channel *ast)
146 {
147         ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
148         return -1;
149 }
150
151 static struct ast_frame  *agent_read(struct ast_channel *ast)
152 {
153         struct agent_pvt *p = ast->pvt->pvt;
154         struct ast_frame *f = NULL;
155         ast_pthread_mutex_lock(&p->lock);
156         if (p->chan)
157                 f = ast_read(p->chan);
158         if (!f) {
159                 /* If there's a channel, make it NULL */
160                 if (p->chan)
161                         p->chan = NULL;
162         }
163         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
164                 /* * terminates call */
165                 ast_frfree(f);
166                 f = NULL;
167         }
168         CLEANUP(ast,p);
169         ast_pthread_mutex_unlock(&p->lock);
170         return f;
171 }
172
173 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
174 {
175         struct agent_pvt *p = ast->pvt->pvt;
176         int res = -1;
177         ast_pthread_mutex_lock(&p->lock);
178         if (p->chan)
179                 res = ast_write(p->chan, f);
180         CLEANUP(ast, p);
181         ast_pthread_mutex_unlock(&p->lock);
182         return res;
183 }
184
185 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
186 {
187         struct agent_pvt *p = newchan->pvt->pvt;
188         ast_pthread_mutex_lock(&p->lock);
189         if (p->owner != oldchan) {
190                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
191                 ast_pthread_mutex_unlock(&p->lock);
192                 return -1;
193         }
194         p->owner = newchan;
195         ast_pthread_mutex_unlock(&p->lock);
196         return 0;
197 }
198
199 static int agent_indicate(struct ast_channel *ast, int condition)
200 {
201         struct agent_pvt *p = ast->pvt->pvt;
202         int res = -1;
203         ast_pthread_mutex_lock(&p->lock);
204         if (p->chan)
205                 res = ast_indicate(p->chan, condition);
206         ast_pthread_mutex_unlock(&p->lock);
207         return res;
208 }
209
210 static int agent_digit(struct ast_channel *ast, char digit)
211 {
212         struct agent_pvt *p = ast->pvt->pvt;
213         int res = -1;
214         ast_pthread_mutex_lock(&p->lock);
215         if (p->chan)
216                 res = p->chan->pvt->send_digit(p->chan, digit);
217         ast_pthread_mutex_unlock(&p->lock);
218         return res;
219 }
220
221 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
222 {
223         struct agent_pvt *p = ast->pvt->pvt;
224         int res = -1;
225         ast_pthread_mutex_lock(&p->lock);
226         ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
227         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
228         res = ast_streamfile(p->chan, "beep", p->chan->language);
229         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
230         if (!res) {
231                 res = ast_waitstream(p->chan, "");
232                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
233         }
234         if (!res) {
235                 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
236                 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
237                 if (res)
238                         ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(p->chan->nativeformats));
239         }
240         else {
241                 // Agent hung-up
242                 p->chan = NULL;
243         }
244
245         if (!res) {
246                 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
247                 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
248                 if (res)
249                         ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(p->chan->nativeformats));
250         }
251         if( !res )
252         {
253                 /* Call is immediately up */
254                 ast_setstate(ast, AST_STATE_UP);
255         }
256         CLEANUP(ast,p);
257         ast_pthread_mutex_unlock(&p->lock);
258         return res;
259 }
260
261 static int agent_hangup(struct ast_channel *ast)
262 {
263         struct agent_pvt *p = ast->pvt->pvt;
264         ast_pthread_mutex_lock(&p->lock);
265         p->owner = NULL;
266         ast->pvt->pvt = NULL;
267         p->app_sleep_cond = 1;
268         if (p->chan) {
269                 /* If they're dead, go ahead and hang up on the agent now */
270                 ast_pthread_mutex_lock(&p->chan->lock);
271                 if (p->dead)
272                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
273                 ast_moh_start(p->chan, p->moh);
274                 ast_pthread_mutex_unlock(&p->chan->lock);
275                 ast_pthread_mutex_unlock(&p->lock);
276                 /* Release ownership of the agent to other threads (presumably running the login app). */
277                 ast_pthread_mutex_unlock(&p->app_lock);
278         } else if (p->dead) {
279                 /* Go ahead and lose it */
280                 ast_pthread_mutex_unlock(&p->lock);
281                 /* Release ownership of the agent to other threads (presumably running the login app). */
282                 ast_pthread_mutex_unlock(&p->app_lock);
283                 free(p);
284         } else {
285                 ast_pthread_mutex_unlock(&p->lock);
286                 /* Release ownership of the agent to other threads (presumably running the login app). */
287                 ast_pthread_mutex_unlock(&p->app_lock);
288         }
289
290         return 0;
291 }
292
293 static int agent_cont_sleep( void *data )
294 {
295         struct agent_pvt *p;
296         int res;
297
298         p = (struct agent_pvt *)data;
299
300         ast_pthread_mutex_lock(&p->lock);
301         res = p->app_sleep_cond;
302         ast_pthread_mutex_unlock(&p->lock);
303         if( !res )
304                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
305         return res;
306 }
307
308 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
309 {
310         struct ast_channel *tmp;
311         struct ast_frame null_frame = { AST_FRAME_NULL };
312         if (!p->chan) {
313                 ast_log(LOG_WARNING, "No channel? :(\n");
314                 return NULL;
315         }
316         tmp = ast_channel_alloc(0);
317         if (tmp) {
318                 tmp->nativeformats = p->chan->nativeformats;
319                 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
320                 tmp->type = type;
321                 ast_setstate(tmp, state);
322                 tmp->writeformat = p->chan->writeformat;
323                 tmp->pvt->rawwriteformat = p->chan->writeformat;
324                 tmp->readformat = p->chan->readformat;
325                 tmp->pvt->rawreadformat = p->chan->readformat;
326                 tmp->pvt->pvt = p;
327                 tmp->pvt->send_digit = agent_digit;
328                 tmp->pvt->call = agent_call;
329                 tmp->pvt->hangup = agent_hangup;
330                 tmp->pvt->answer = agent_answer;
331                 tmp->pvt->read = agent_read;
332                 tmp->pvt->write = agent_write;
333                 tmp->pvt->exception = agent_read;
334                 tmp->pvt->indicate = agent_indicate;
335                 tmp->pvt->fixup = agent_fixup;
336                 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
337                 p->owner = tmp;
338                 ast_pthread_mutex_lock(&usecnt_lock);
339                 usecnt++;
340                 ast_pthread_mutex_unlock(&usecnt_lock);
341                 ast_update_use_count();
342                 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
343                 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
344                 tmp->priority = 1;
345                 /* Wake up and wait for other applications (by definition the login app)
346                  * to release this channel). Takes ownership of the agent channel
347                  * to this thread only.
348                  * For signalling the other thread, ast_queue_frame is used until we
349                  * can safely use signals for this purpose. The pselect() needs to be
350                  * implemented in the kernel for this.
351                  */
352                 p->app_sleep_cond = 0;
353                 if( pthread_mutex_trylock(&p->app_lock) )
354                 {
355                         ast_queue_frame(p->chan, &null_frame, 1);
356                         ast_pthread_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
357                         ast_pthread_mutex_lock(&p->app_lock);
358                         ast_pthread_mutex_lock(&p->lock);
359                         if( !p->chan )
360                         {
361                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
362                                 p->owner = NULL;
363                                 tmp->pvt->pvt = NULL;
364                                 p->app_sleep_cond = 1;
365                                 ast_channel_free( tmp );
366                                 return NULL;
367                         }
368                 }
369                 p->owning_app = pthread_self();
370                 /* After the above step, there should not be any blockers. */
371                 if (p->chan->blocking) {
372                         ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
373                         CRASH;
374                 }
375                 ast_moh_stop(p->chan);
376         } else
377                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
378         return tmp;
379 }
380
381
382 static int read_agent_config(void)
383 {
384         struct ast_config *cfg;
385         struct ast_variable *v;
386         struct agent_pvt *p, *pl, *pn;
387         cfg = ast_load(config);
388         if (!cfg) {
389                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
390                 return 0;
391         }
392         ast_pthread_mutex_lock(&agentlock);
393         p = agents;
394         while(p) {
395                 p->dead = 1;
396                 p = p->next;
397         }
398         strcpy(moh, "default");
399         v = ast_variable_browse(cfg, "agents");
400         while(v) {
401                 /* Create the interface list */
402                 if (!strcasecmp(v->name, "agent")) {
403                         add_agent(v);
404                 } else if (!strcasecmp(v->name, "musiconhold")) {
405                         strncpy(moh, v->value, sizeof(moh) - 1);
406                 }
407                 v = v->next;
408         }
409         p = agents;
410         pl = NULL;
411         while(p) {
412                 pn = p->next;
413                 if (p->dead) {
414                         /* Unlink */
415                         if (pl)
416                                 pl->next = p->next;
417                         else
418                                 agents = p->next;
419                         /* Destroy if  appropriate */
420                         if (!p->owner) {
421                                 if (!p->chan) {
422                                         free(p);
423                                 } else {
424                                         /* Cause them to hang up */
425                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
426                                 }
427                         }
428                 } else
429                         pl = p;
430                 p = pn;
431         }
432         ast_pthread_mutex_unlock(&agentlock);
433         ast_destroy(cfg);
434         return 0;
435 }
436
437 static struct ast_channel *agent_request(char *type, int format, void *data)
438 {
439         struct agent_pvt *p;
440         struct ast_channel *chan = NULL;
441         ast_pthread_mutex_lock(&agentlock);
442         p = agents;
443         while(p) {
444                 if (!strcmp(data, p->agent)) {
445                         ast_pthread_mutex_lock(&p->lock);
446                         /* Agent must be registered, but not have any active call */
447                         if (!p->owner && p->chan) {
448                                 chan = agent_new(p, AST_STATE_DOWN);
449                         }
450                         ast_pthread_mutex_unlock(&p->lock);
451                         break;
452                 }
453                 p = p->next;
454         }
455         ast_pthread_mutex_unlock(&agentlock);
456         return chan;
457 }
458
459 static int agents_show(int fd, int argc, char **argv)
460 {
461         struct agent_pvt *p;
462         char username[256];
463         char location[256];
464         char talkingto[256];
465
466         if (argc != 2)
467                 return RESULT_SHOWUSAGE;
468         ast_pthread_mutex_lock(&agentlock);
469         p = agents;
470         while(p) {
471                 ast_pthread_mutex_lock(&p->lock);
472                 if (strlen(p->name))
473                         snprintf(username, sizeof(username), "(%s) ", p->name);
474                 else
475                         strcpy(username, "");
476                 if (p->chan) {
477                         snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
478                         if (p->owner && p->owner->bridge) {
479                                 snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
480                         } else {
481                                 strcpy(talkingto, " is idle");
482                         }
483                 } else {
484                         strcpy(location, "not logged in");
485                         strcpy(talkingto, "");
486                 }
487                 ast_pthread_mutex_unlock(&p->lock);
488                 ast_cli(fd, "%-12.12s %s%s%s\n", p->agent, 
489                                 username, location, talkingto);
490                 p = p->next;
491         }
492         ast_pthread_mutex_unlock(&agentlock);
493         return RESULT_SUCCESS;
494 }
495
496 static char show_agents_usage[] = 
497 "Usage: show agents\n"
498 "       Provides summary information on agents.\n";
499
500 static struct ast_cli_entry cli_show_agents = {
501         { "show", "agents", NULL }, agents_show, 
502         "Show status of agents", show_agents_usage, NULL };
503
504 STANDARD_LOCAL_USER;
505 LOCAL_USER_DECL;
506
507 static int login_exec(struct ast_channel *chan, void *data)
508 {
509         int res=0;
510         int tries = 0;
511         struct agent_pvt *p;
512         struct localuser *u;
513         char user[AST_MAX_AGENT];
514         char pass[AST_MAX_AGENT];
515         char xpass[AST_MAX_AGENT] = "";
516         char *errmsg;
517         char info[512];
518         char *opt_user = NULL;
519         char *options = NULL;
520         int play_announcement;
521         
522         LOCAL_USER_ADD(u);
523
524         /* Parse the arguments XXX Check for failure XXX */
525         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
526         opt_user = info;
527         if( opt_user ) {
528                 options = strchr(opt_user, '|');
529                 if (options) {
530                         *options = '\0';
531                         options++;
532                 }
533         }
534
535         if (chan->_state != AST_STATE_UP)
536                 res = ast_answer(chan);
537         if (!res) {
538                 if( opt_user )
539                         strncpy( user, opt_user, AST_MAX_AGENT );
540                 else
541                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
542         }
543         while (!res && (tries < 3)) {
544                 /* Check for password */
545                 ast_pthread_mutex_lock(&agentlock);
546                 p = agents;
547                 while(p) {
548                         if (!strcmp(p->agent, user))
549                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
550                         p = p->next;
551                 }
552                 ast_pthread_mutex_unlock(&agentlock);
553                 if (!res) {
554                         if (strlen(xpass))
555                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
556                         else
557                                 strcpy(pass, "");
558                 }
559                 errmsg = "agent-incorrect";
560
561 #if 0
562                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
563 #endif          
564
565                 /* Check again for accuracy */
566                 ast_pthread_mutex_lock(&agentlock);
567                 p = agents;
568                 while(p) {
569                         ast_pthread_mutex_lock(&p->lock);
570                         if (!strcmp(p->agent, user) &&
571                                 !strcmp(p->password, pass)) {
572                                         if (!p->chan) {
573                                                 play_announcement = 1;
574                                                 if( options )
575                                                         if( strchr( options, 's' ) )
576                                                                 play_announcement = 0;
577                                                 if( play_announcement )
578                                                         res = ast_streamfile(chan, "agent-loginok", chan->language);
579                                                 if (!res)
580                                                         ast_waitstream(chan, "");
581                                                 if (!res) {
582                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
583                                                         if (res)
584                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
585                                                 }
586                                                 if (!res) {
587                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
588                                                         if (res)
589                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
590                                                 }
591                                                 /* Check once more just in case */
592                                                 if (p->chan)
593                                                         res = -1;
594                                                 if (!res) {
595                                                         /* check if the moh class was changed with setmusiconhold */
596                                                         if (*(chan->musicclass))
597                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
598                                                         ast_moh_start(chan, p->moh);
599                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
600                                                                 "Agent: %s\r\n"
601                                                                 "Channel: %s\r\n",
602                                                                 p->agent, chan->name);
603                                                         if (option_verbose > 2)
604                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %d/%d)\n", p->agent,
605                                                                                                 chan->readformat, chan->writeformat);
606                                                         /* Login this channel and wait for it to
607                                                            go away */
608                                                         p->chan = chan;
609                                                         ast_pthread_mutex_unlock(&p->lock);
610                                                         ast_pthread_mutex_unlock(&agentlock);
611                                                         while (res >= 0) {
612                                                                 ast_pthread_mutex_lock(&p->lock);
613                                                                 if (p->chan != chan)
614                                                                         res = -1;
615                                                                 ast_pthread_mutex_unlock(&p->lock);
616                                                                 /* Yield here so other interested threads can kick in. */
617                                                                 sched_yield();
618                                                                 if (res)
619                                                                         break;
620
621                                                                 /*      Synchronize channel ownership between call to agent and itself. */
622                                                                 pthread_mutex_lock( &p->app_lock );
623                                                                 ast_pthread_mutex_lock(&p->lock);
624                                                                 p->owning_app = pthread_self();
625                                                                 ast_pthread_mutex_unlock(&p->lock);
626                                                                 res = ast_safe_sleep_conditional( chan, 1000,
627                                                                                                                 agent_cont_sleep, p );
628                                                                 pthread_mutex_unlock( &p->app_lock );
629                                                                 sched_yield();
630                                                         }
631                                                         ast_pthread_mutex_lock(&p->lock);
632                                                         if (res && p->owner) 
633                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
634                                                         /* Log us off if appropriate */
635                                                         if (p->chan == chan)
636                                                                 p->chan = NULL;
637                                                         ast_pthread_mutex_unlock(&p->lock);
638                                                         if (option_verbose > 2)
639                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
640                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
641                                                                 "Agent: %s\r\n",
642                                                                 p->agent);
643                                                         /* If there is no owner, go ahead and kill it now */
644                                                         if (p->dead && !p->owner)
645                                                                 free(p);
646                                                 }
647                                                 else {
648                                                         ast_pthread_mutex_unlock(&p->lock);
649                                                         p = NULL;
650                                                 }
651                                                 res = -1;
652                                         } else {
653                                                 ast_pthread_mutex_unlock(&p->lock);
654                                                 errmsg = "agent-alreadyon";
655                                                 p = NULL;
656                                         }
657                                         break;
658                         }
659                         ast_pthread_mutex_unlock(&p->lock);
660                         p = p->next;
661                 }
662                 if (!p)
663                         ast_pthread_mutex_unlock(&agentlock);
664
665                 if (!res)
666                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
667         }
668                 
669         LOCAL_USER_REMOVE(u);
670         /* Always hangup */
671         return -1;
672 }
673
674
675 int load_module()
676 {
677         /* Make sure we can register our sip channel type */
678         if (ast_channel_register(type, tdesc, capability, agent_request)) {
679                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
680                 return -1;
681         }
682         ast_register_application(app, login_exec, synopsis, descrip);
683         ast_cli_register(&cli_show_agents);
684         /* Read in the config */
685         read_agent_config();
686         return 0;
687 }
688
689 int reload()
690 {
691         read_agent_config();
692         return 0;
693 }
694
695 int unload_module()
696 {
697         struct agent_pvt *p;
698         /* First, take us out of the channel loop */
699         ast_cli_unregister(&cli_show_agents);
700         ast_unregister_application(app);
701         ast_channel_unregister(type);
702         if (!ast_pthread_mutex_lock(&agentlock)) {
703                 /* Hangup all interfaces if they have an owner */
704                 p = agents;
705                 while(p) {
706                         if (p->owner)
707                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
708                         p = p->next;
709                 }
710                 agents = NULL;
711                 ast_pthread_mutex_unlock(&agentlock);
712         } else {
713                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
714                 return -1;
715         }               
716         return 0;
717 }
718
719 int usecount()
720 {
721         int res;
722         ast_pthread_mutex_lock(&usecnt_lock);
723         res = usecnt;
724         ast_pthread_mutex_unlock(&usecnt_lock);
725         return res;
726 }
727
728 char *key()
729 {
730         return ASTERISK_GPL_KEY;
731 }
732
733 char *description()
734 {
735         return desc;
736 }
737