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