Fix race in Agents
[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         int pending;                                            /* Not a real agent -- just pending a match */
82         int abouttograb;                                        /* About to grab */
83         unsigned int group;                                     /* Group memberships */
84         char moh[80];                                           /* Which music on hold */
85         char agent[AST_MAX_AGENT];                      /* Agent ID */
86         char password[AST_MAX_AGENT];           /* Password for Agent login */
87         char name[AST_MAX_AGENT];
88         pthread_mutex_t app_lock;                       /* Synchronization between owning applications */
89         volatile pthread_t owning_app;          /* Owning application thread id */
90         volatile int app_sleep_cond;            /* Sleep condition for the login app */
91         struct ast_channel *owner;                      /* Agent */
92         struct ast_channel *chan;                       /* Channel we use */
93         struct agent_pvt *next;                         /* Agent */
94 } *agents = NULL;
95
96 #define CLEANUP(ast, p) do { \
97         int x; \
98         if (p->chan) { \
99                 for (x=0;x<AST_MAX_FDS;x++) \
100                         ast->fds[x] = p->chan->fds[x]; \
101         } \
102 } while(0)
103
104
105 static void agent_unlink(struct agent_pvt *agent)
106 {
107         struct agent_pvt *p, *prev;
108         prev = NULL;
109         p = agents;
110         while(p) {
111                 if (p == agent) {
112                         if (prev)
113                                 prev->next = agent->next;
114                         else
115                                 agents = agent->next;
116                         break;
117                 }
118                 prev = p;
119                 p = p->next;
120         }
121 }
122
123 static struct agent_pvt *add_agent(char *agent, int pending)
124 {
125         char tmp[256];
126         char *password=NULL, *name=NULL;
127         struct agent_pvt *p, *prev;
128         
129         strncpy(tmp, agent, sizeof(tmp));
130         if ((password = strchr(tmp, ','))) {
131                 *password = '\0';
132                 password++;
133                 while (*password < 33) password++;
134         }
135         if (password && (name = strchr(password, ','))) {
136                 *name = '\0';
137                 name++;
138                 while (*name < 33) name++; 
139         }
140         prev=NULL;
141         p = agents;
142         while(p) {
143                 if (!pending && !strcmp(p->agent, tmp))
144                         break;
145                 prev = p;
146                 p = p->next;
147         }
148         if (!p) {
149                 p = malloc(sizeof(struct agent_pvt));
150                 if (p) {
151                         memset(p, 0, sizeof(struct agent_pvt));
152                         strncpy(p->agent, tmp, sizeof(p->agent) -1);
153                         ast_pthread_mutex_init( &p->lock );
154                         ast_pthread_mutex_init( &p->app_lock );
155                         p->owning_app = -1;
156                         p->app_sleep_cond = 1;
157                         p->group = group;
158                         p->pending = pending;
159                         p->next = NULL;
160                         if (prev)
161                                 prev->next = p;
162                         else
163                                 agents = p;
164                         
165                 }
166         }
167         if (!p)
168                 return NULL;
169         strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
170         strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
171         strncpy(p->moh, moh, sizeof(p->moh) - 1);
172         if (pending)
173                 p->dead = 1;
174         else
175                 p->dead = 0;
176         return p;
177 }
178
179 static int agent_cleanup(struct agent_pvt *p)
180 {
181         struct ast_channel *chan = p->owner;
182         p->owner = NULL;
183         chan->pvt->pvt = NULL;
184         p->app_sleep_cond = 1;
185         /* Release ownership of the agent to other threads (presumably running the login app). */
186         ast_pthread_mutex_unlock(&p->app_lock);
187         if (chan)
188                 ast_channel_free(chan);
189         if (p->dead)
190                 free(p);
191         return 0;
192 }
193
194 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
195
196 static int agent_answer(struct ast_channel *ast)
197 {
198         ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
199         return -1;
200 }
201
202 static struct ast_frame  *agent_read(struct ast_channel *ast)
203 {
204         struct agent_pvt *p = ast->pvt->pvt;
205         struct ast_frame *f = NULL;
206         static struct ast_frame null_frame = { AST_FRAME_NULL, };
207         ast_pthread_mutex_lock(&p->lock);
208         if (p->chan)
209                 f = ast_read(p->chan);
210         else
211                 f = &null_frame;
212         if (!f) {
213                 /* If there's a channel, make it NULL */
214                 if (p->chan)
215                         p->chan = NULL;
216         }
217         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
218                 /* * terminates call */
219                 ast_frfree(f);
220                 f = NULL;
221         }
222         CLEANUP(ast,p);
223         ast_pthread_mutex_unlock(&p->lock);
224         return f;
225 }
226
227 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
228 {
229         struct agent_pvt *p = ast->pvt->pvt;
230         int res = -1;
231         ast_pthread_mutex_lock(&p->lock);
232         if (p->chan)
233                 res = ast_write(p->chan, f);
234         else
235                 res = 0;
236         CLEANUP(ast, p);
237         ast_pthread_mutex_unlock(&p->lock);
238         return res;
239 }
240
241 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
242 {
243         struct agent_pvt *p = newchan->pvt->pvt;
244         ast_pthread_mutex_lock(&p->lock);
245         if (p->owner != oldchan) {
246                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
247                 ast_pthread_mutex_unlock(&p->lock);
248                 return -1;
249         }
250         p->owner = newchan;
251         ast_pthread_mutex_unlock(&p->lock);
252         return 0;
253 }
254
255 static int agent_indicate(struct ast_channel *ast, int condition)
256 {
257         struct agent_pvt *p = ast->pvt->pvt;
258         int res = -1;
259         ast_pthread_mutex_lock(&p->lock);
260         if (p->chan)
261                 res = ast_indicate(p->chan, condition);
262         else
263                 res = 0;
264         ast_pthread_mutex_unlock(&p->lock);
265         return res;
266 }
267
268 static int agent_digit(struct ast_channel *ast, char digit)
269 {
270         struct agent_pvt *p = ast->pvt->pvt;
271         int res = -1;
272         ast_pthread_mutex_lock(&p->lock);
273         if (p->chan)
274                 res = p->chan->pvt->send_digit(p->chan, digit);
275         else
276                 res = 0;
277         ast_pthread_mutex_unlock(&p->lock);
278         return res;
279 }
280
281 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
282 {
283         struct agent_pvt *p = ast->pvt->pvt;
284         int res = -1;
285         ast_pthread_mutex_lock(&p->lock);
286         if (!p->chan) {
287                 if (p->pending) {
288                         ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
289                         ast_setstate(ast, AST_STATE_DIALING);
290                         res = 0;
291                 } else {
292                         ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
293                         res = -1;
294                 }
295                 ast_pthread_mutex_unlock(&p->lock);
296                 return res;
297         }
298         ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
299         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
300         res = ast_streamfile(p->chan, "beep", p->chan->language);
301         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
302         if (!res) {
303                 res = ast_waitstream(p->chan, "");
304                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
305         }
306         if (!res) {
307                 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
308                 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
309                 if (res)
310                         ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(p->chan->nativeformats));
311         } else {
312                 // Agent hung-up
313                 p->chan = NULL;
314         }
315
316         if (!res) {
317                 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
318                 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
319                 if (res)
320                         ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(p->chan->nativeformats));
321         }
322         if( !res )
323         {
324                 /* Call is immediately up */
325                 ast_setstate(ast, AST_STATE_UP);
326         }
327         CLEANUP(ast,p);
328         ast_pthread_mutex_unlock(&p->lock);
329         return res;
330 }
331
332 static int agent_hangup(struct ast_channel *ast)
333 {
334         struct agent_pvt *p = ast->pvt->pvt;
335         ast_pthread_mutex_lock(&p->lock);
336         p->owner = NULL;
337         ast->pvt->pvt = NULL;
338         p->app_sleep_cond = 1;
339         if (p->chan) {
340                 /* If they're dead, go ahead and hang up on the agent now */
341                 ast_pthread_mutex_lock(&p->chan->lock);
342                 if (p->dead)
343                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
344                 ast_moh_start(p->chan, p->moh);
345                 ast_pthread_mutex_unlock(&p->chan->lock);
346         }
347 #if 0
348                 ast_pthread_mutex_unlock(&p->lock);
349                 /* Release ownership of the agent to other threads (presumably running the login app). */
350                 ast_pthread_mutex_unlock(&p->app_lock);
351         } else if (p->dead) {
352                 /* Go ahead and lose it */
353                 ast_pthread_mutex_unlock(&p->lock);
354                 /* Release ownership of the agent to other threads (presumably running the login app). */
355                 ast_pthread_mutex_unlock(&p->app_lock);
356         } else {
357                 ast_pthread_mutex_unlock(&p->lock);
358                 /* Release ownership of the agent to other threads (presumably running the login app). */
359                 ast_pthread_mutex_unlock(&p->app_lock);
360         }
361 #endif  
362         ast_pthread_mutex_unlock(&p->lock);
363         /* Release ownership of the agent to other threads (presumably running the login app). */
364         ast_pthread_mutex_unlock(&p->app_lock);
365
366         if (p->pending) {
367                 ast_pthread_mutex_lock(&agentlock);
368                 agent_unlink(p);
369                 ast_pthread_mutex_unlock(&agentlock);
370         }
371         if (p->abouttograb) {
372                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
373                    kill it later */
374                 p->abouttograb = 0;
375         } else if (p->dead) {
376                 free(p);
377         } else {
378                 /* Not dead -- check availability now */
379                 ast_pthread_mutex_lock(&p->lock);
380                 check_availability(p, 1);
381                 ast_pthread_mutex_unlock(&p->lock);
382         }
383         return 0;
384 }
385
386 static int agent_cont_sleep( void *data )
387 {
388         struct agent_pvt *p;
389         int res;
390
391         p = (struct agent_pvt *)data;
392
393         ast_pthread_mutex_lock(&p->lock);
394         res = p->app_sleep_cond;
395         ast_pthread_mutex_unlock(&p->lock);
396 #if 0
397         if( !res )
398                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
399 #endif          
400         return res;
401 }
402
403 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
404 {
405         struct ast_channel *tmp;
406         struct ast_frame null_frame = { AST_FRAME_NULL };
407 #if 0
408         if (!p->chan) {
409                 ast_log(LOG_WARNING, "No channel? :(\n");
410                 return NULL;
411         }
412 #endif  
413         tmp = ast_channel_alloc(0);
414         if (tmp) {
415                 if (p->chan) {
416                         tmp->nativeformats = p->chan->nativeformats;
417                         tmp->writeformat = p->chan->writeformat;
418                         tmp->pvt->rawwriteformat = p->chan->writeformat;
419                         tmp->readformat = p->chan->readformat;
420                         tmp->pvt->rawreadformat = p->chan->readformat;
421                         strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
422                         strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
423                         strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
424                 } else {
425                         tmp->nativeformats = AST_FORMAT_SLINEAR;
426                         tmp->writeformat = AST_FORMAT_SLINEAR;
427                         tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
428                         tmp->readformat = AST_FORMAT_SLINEAR;
429                         tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
430                 }
431                 if (p->pending)
432                         snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
433                 else
434                         snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
435                 tmp->type = type;
436                 ast_setstate(tmp, state);
437                 tmp->pvt->pvt = p;
438                 tmp->pvt->send_digit = agent_digit;
439                 tmp->pvt->call = agent_call;
440                 tmp->pvt->hangup = agent_hangup;
441                 tmp->pvt->answer = agent_answer;
442                 tmp->pvt->read = agent_read;
443                 tmp->pvt->write = agent_write;
444                 tmp->pvt->exception = agent_read;
445                 tmp->pvt->indicate = agent_indicate;
446                 tmp->pvt->fixup = agent_fixup;
447                 p->owner = tmp;
448                 ast_pthread_mutex_lock(&usecnt_lock);
449                 usecnt++;
450                 ast_pthread_mutex_unlock(&usecnt_lock);
451                 ast_update_use_count();
452                 tmp->priority = 1;
453                 /* Wake up and wait for other applications (by definition the login app)
454                  * to release this channel). Takes ownership of the agent channel
455                  * to this thread only.
456                  * For signalling the other thread, ast_queue_frame is used until we
457                  * can safely use signals for this purpose. The pselect() needs to be
458                  * implemented in the kernel for this.
459                  */
460                 p->app_sleep_cond = 0;
461                 if( pthread_mutex_trylock(&p->app_lock) )
462                 {
463                         if (p->chan) {
464                                 ast_queue_frame(p->chan, &null_frame, 1);
465                                 ast_pthread_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
466                                 ast_pthread_mutex_lock(&p->app_lock);
467                                 ast_pthread_mutex_lock(&p->lock);
468                         }
469                         if( !p->chan )
470                         {
471                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
472                                 p->owner = NULL;
473                                 tmp->pvt->pvt = NULL;
474                                 p->app_sleep_cond = 1;
475                                 ast_channel_free( tmp );
476                                 return NULL;
477                         }
478                 }
479                 p->owning_app = pthread_self();
480                 /* After the above step, there should not be any blockers. */
481                 if (p->chan) {
482                         if (p->chan->blocking) {
483                                 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
484                                 CRASH;
485                         }
486                         ast_moh_stop(p->chan);
487                 }
488         } else
489                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
490         return tmp;
491 }
492
493
494 static int read_agent_config(void)
495 {
496         struct ast_config *cfg;
497         struct ast_variable *v;
498         struct agent_pvt *p, *pl, *pn;
499         group = 0;
500         cfg = ast_load(config);
501         if (!cfg) {
502                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
503                 return 0;
504         }
505         ast_pthread_mutex_lock(&agentlock);
506         p = agents;
507         while(p) {
508                 p->dead = 1;
509                 p = p->next;
510         }
511         strcpy(moh, "default");
512         v = ast_variable_browse(cfg, "agents");
513         while(v) {
514                 /* Create the interface list */
515                 if (!strcasecmp(v->name, "agent")) {
516                         add_agent(v->value, 0);
517                 } else if (!strcasecmp(v->name, "group")) {
518                         group = ast_get_group(v->value);
519                 } else if (!strcasecmp(v->name, "musiconhold")) {
520                         strncpy(moh, v->value, sizeof(moh) - 1);
521                 }
522                 v = v->next;
523         }
524         p = agents;
525         pl = NULL;
526         while(p) {
527                 pn = p->next;
528                 if (p->dead) {
529                         /* Unlink */
530                         if (pl)
531                                 pl->next = p->next;
532                         else
533                                 agents = p->next;
534                         /* Destroy if  appropriate */
535                         if (!p->owner) {
536                                 if (!p->chan) {
537                                         free(p);
538                                 } else {
539                                         /* Cause them to hang up */
540                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
541                                 }
542                         }
543                 } else
544                         pl = p;
545                 p = pn;
546         }
547         ast_pthread_mutex_unlock(&agentlock);
548         ast_destroy(cfg);
549         return 0;
550 }
551
552 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
553 {
554         struct ast_channel *chan=NULL, *parent=NULL;
555         struct agent_pvt *p;
556         int res;
557         ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
558         if (needlock)
559                 ast_pthread_mutex_lock(&agentlock);
560         p = agents;
561         while(p) {
562                 if (p == newlyavailable) {
563                         p = p->next;
564                         continue;
565                 }
566                 ast_pthread_mutex_lock(&p->lock);
567                 if (p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
568                         ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
569                         /* We found a pending call, time to merge */
570                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
571                         parent = p->owner;
572                         p->abouttograb = 1;
573                         ast_pthread_mutex_unlock(&p->lock);
574                         break;
575                 }
576                 ast_pthread_mutex_unlock(&p->lock);
577                 p = p->next;
578         }
579         if (needlock)
580                 ast_pthread_mutex_unlock(&agentlock);
581         if (parent && chan)  {
582                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
583                 res = ast_streamfile(newlyavailable->chan, "beep", newlyavailable->chan->language);
584                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
585                 if (!res) {
586                         res = ast_waitstream(newlyavailable->chan, "");
587                         ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
588                 }
589                 if (!res) {
590                         /* Note -- parent may have disappeared */
591                         if (p->abouttograb) {
592                                 ast_setstate(parent, AST_STATE_UP);
593                                 ast_setstate(chan, AST_STATE_UP);
594                                 ast_channel_masquerade(parent, chan);
595                                 p->abouttograb = 0;
596                                 ast_hangup(chan);
597                         } else {
598                                 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
599                                 agent_cleanup(newlyavailable);
600                         }
601                 } else {
602                         ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
603                         agent_cleanup(newlyavailable);
604                 }
605         }
606         return 0;
607 }
608
609 static struct ast_channel *agent_request(char *type, int format, void *data)
610 {
611         struct agent_pvt *p;
612         struct ast_channel *chan = NULL;
613         char *s;
614         unsigned int groupmatch;
615         int waitforagent=0;
616         s = data;
617         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
618                 groupmatch = (1 << groupmatch);
619         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
620                 groupmatch = (1 << groupmatch);
621                 waitforagent = 1;
622         } else {
623                 groupmatch = 0;
624         }
625         ast_pthread_mutex_lock(&agentlock);
626         p = agents;
627         while(p) {
628                 ast_pthread_mutex_lock(&p->lock);
629                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
630                         /* Agent must be registered, but not have any active call */
631                         if (!p->owner && p->chan) {
632                                 chan = agent_new(p, AST_STATE_DOWN);
633                         }
634                         ast_pthread_mutex_unlock(&p->lock);
635                         break;
636                 }
637                 ast_pthread_mutex_unlock(&p->lock);
638                 p = p->next;
639         }
640         if (!chan && waitforagent) {
641                 /* No agent available -- but we're requesting to wait for one.
642                    Allocate a place holder */
643                 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
644                 p = add_agent(data, 1);
645                 p->group = groupmatch;
646                 chan = agent_new(p, AST_STATE_DOWN);
647                 if (!chan) {
648                         ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
649                 }
650         }
651         ast_pthread_mutex_unlock(&agentlock);
652         return chan;
653 }
654
655 static int powerof(unsigned int v)
656 {
657         int x;
658         for (x=0;x<32;x++) {
659                 if (v & (1 << x)) return x;
660         }
661         return 0;
662 }
663
664 static int agents_show(int fd, int argc, char **argv)
665 {
666         struct agent_pvt *p;
667         char username[256];
668         char location[256];
669         char talkingto[256];
670
671         if (argc != 2)
672                 return RESULT_SHOWUSAGE;
673         ast_pthread_mutex_lock(&agentlock);
674         p = agents;
675         while(p) {
676                 ast_pthread_mutex_lock(&p->lock);
677                 if (p->pending) {
678                         if (p->group)
679                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
680                         else
681                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
682                 } else {
683                         if (strlen(p->name))
684                                 snprintf(username, sizeof(username), "(%s) ", p->name);
685                         else
686                                 strcpy(username, "");
687                         if (p->chan) {
688                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
689                                 if (p->owner && p->owner->bridge) {
690                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
691                                 } else {
692                                         strcpy(talkingto, " is idle");
693                                 }
694                         } else {
695                                 strcpy(location, "not logged in");
696                                 strcpy(talkingto, "");
697                         }
698                         ast_cli(fd, "%-12.12s %s%s%s\n", p->agent, 
699                                         username, location, talkingto);
700                 }
701                 ast_pthread_mutex_unlock(&p->lock);
702                 p = p->next;
703         }
704         ast_pthread_mutex_unlock(&agentlock);
705         return RESULT_SUCCESS;
706 }
707
708 static char show_agents_usage[] = 
709 "Usage: show agents\n"
710 "       Provides summary information on agents.\n";
711
712 static struct ast_cli_entry cli_show_agents = {
713         { "show", "agents", NULL }, agents_show, 
714         "Show status of agents", show_agents_usage, NULL };
715
716 STANDARD_LOCAL_USER;
717 LOCAL_USER_DECL;
718
719 static int login_exec(struct ast_channel *chan, void *data)
720 {
721         int res=0;
722         int tries = 0;
723         struct agent_pvt *p;
724         struct localuser *u;
725         char user[AST_MAX_AGENT];
726         char pass[AST_MAX_AGENT];
727         char xpass[AST_MAX_AGENT] = "";
728         char *errmsg;
729         char info[512];
730         char *opt_user = NULL;
731         char *options = NULL;
732         int play_announcement;
733         
734         LOCAL_USER_ADD(u);
735
736         /* Parse the arguments XXX Check for failure XXX */
737         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
738         opt_user = info;
739         if( opt_user ) {
740                 options = strchr(opt_user, '|');
741                 if (options) {
742                         *options = '\0';
743                         options++;
744                 }
745         }
746
747         if (chan->_state != AST_STATE_UP)
748                 res = ast_answer(chan);
749         if (!res) {
750                 if( opt_user && strlen(opt_user))
751                         strncpy( user, opt_user, AST_MAX_AGENT );
752                 else
753                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
754         }
755         while (!res && (tries < 3)) {
756                 /* Check for password */
757                 ast_pthread_mutex_lock(&agentlock);
758                 p = agents;
759                 while(p) {
760                         if (!strcmp(p->agent, user) && !p->pending)
761                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
762                         p = p->next;
763                 }
764                 ast_pthread_mutex_unlock(&agentlock);
765                 if (!res) {
766                         if (strlen(xpass))
767                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
768                         else
769                                 strcpy(pass, "");
770                 }
771                 errmsg = "agent-incorrect";
772
773 #if 0
774                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
775 #endif          
776
777                 /* Check again for accuracy */
778                 ast_pthread_mutex_lock(&agentlock);
779                 p = agents;
780                 while(p) {
781                         ast_pthread_mutex_lock(&p->lock);
782                         if (!strcmp(p->agent, user) &&
783                                 !strcmp(p->password, pass) && !p->pending) {
784                                         if (!p->chan) {
785                                                 play_announcement = 1;
786                                                 if( options )
787                                                         if( strchr( options, 's' ) )
788                                                                 play_announcement = 0;
789                                                 if( play_announcement )
790                                                         res = ast_streamfile(chan, "agent-loginok", chan->language);
791                                                 if (!res)
792                                                         ast_waitstream(chan, "");
793                                                 if (!res) {
794                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
795                                                         if (res)
796                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
797                                                 }
798                                                 if (!res) {
799                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
800                                                         if (res)
801                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
802                                                 }
803                                                 /* Check once more just in case */
804                                                 if (p->chan)
805                                                         res = -1;
806                                                 if (!res) {
807                                                         /* check if the moh class was changed with setmusiconhold */
808                                                         if (*(chan->musicclass))
809                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
810                                                         ast_moh_start(chan, p->moh);
811                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
812                                                                 "Agent: %s\r\n"
813                                                                 "Channel: %s\r\n",
814                                                                 p->agent, chan->name);
815                                                         if (option_verbose > 2)
816                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %d/%d)\n", p->agent,
817                                                                                                 chan->readformat, chan->writeformat);
818                                                         /* Login this channel and wait for it to
819                                                            go away */
820                                                         p->chan = chan;
821                                                         check_availability(p, 0);
822                                                         ast_pthread_mutex_unlock(&p->lock);
823                                                         ast_pthread_mutex_unlock(&agentlock);
824                                                         while (res >= 0) {
825                                                                 ast_pthread_mutex_lock(&p->lock);
826                                                                 if (p->chan != chan)
827                                                                         res = -1;
828                                                                 ast_pthread_mutex_unlock(&p->lock);
829                                                                 /* Yield here so other interested threads can kick in. */
830                                                                 sched_yield();
831                                                                 if (res)
832                                                                         break;
833
834                                                                 /*      Synchronize channel ownership between call to agent and itself. */
835                                                                 pthread_mutex_lock( &p->app_lock );
836                                                                 ast_pthread_mutex_lock(&p->lock);
837                                                                 p->owning_app = pthread_self();
838                                                                 ast_pthread_mutex_unlock(&p->lock);
839                                                                 res = ast_safe_sleep_conditional( chan, 1000,
840                                                                                                                 agent_cont_sleep, p );
841                                                                 pthread_mutex_unlock( &p->app_lock );
842                                                                 sched_yield();
843                                                         }
844                                                         ast_pthread_mutex_lock(&p->lock);
845                                                         if (res && p->owner) 
846                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
847                                                         /* Log us off if appropriate */
848                                                         if (p->chan == chan)
849                                                                 p->chan = NULL;
850                                                         ast_pthread_mutex_unlock(&p->lock);
851                                                         if (option_verbose > 2)
852                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
853                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
854                                                                 "Agent: %s\r\n",
855                                                                 p->agent);
856                                                         /* If there is no owner, go ahead and kill it now */
857                                                         if (p->dead && !p->owner)
858                                                                 free(p);
859                                                 }
860                                                 else {
861                                                         ast_pthread_mutex_unlock(&p->lock);
862                                                         p = NULL;
863                                                 }
864                                                 res = -1;
865                                         } else {
866                                                 ast_pthread_mutex_unlock(&p->lock);
867                                                 errmsg = "agent-alreadyon";
868                                                 p = NULL;
869                                         }
870                                         break;
871                         }
872                         ast_pthread_mutex_unlock(&p->lock);
873                         p = p->next;
874                 }
875                 if (!p)
876                         ast_pthread_mutex_unlock(&agentlock);
877
878                 if (!res)
879                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
880         }
881                 
882         LOCAL_USER_REMOVE(u);
883         /* Always hangup */
884         return -1;
885 }
886
887
888 int load_module()
889 {
890         /* Make sure we can register our sip channel type */
891         if (ast_channel_register(type, tdesc, capability, agent_request)) {
892                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
893                 return -1;
894         }
895         ast_register_application(app, login_exec, synopsis, descrip);
896         ast_cli_register(&cli_show_agents);
897         /* Read in the config */
898         read_agent_config();
899         return 0;
900 }
901
902 int reload()
903 {
904         read_agent_config();
905         return 0;
906 }
907
908 int unload_module()
909 {
910         struct agent_pvt *p;
911         /* First, take us out of the channel loop */
912         ast_cli_unregister(&cli_show_agents);
913         ast_unregister_application(app);
914         ast_channel_unregister(type);
915         if (!ast_pthread_mutex_lock(&agentlock)) {
916                 /* Hangup all interfaces if they have an owner */
917                 p = agents;
918                 while(p) {
919                         if (p->owner)
920                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
921                         p = p->next;
922                 }
923                 agents = NULL;
924                 ast_pthread_mutex_unlock(&agentlock);
925         } else {
926                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
927                 return -1;
928         }               
929         return 0;
930 }
931
932 int usecount()
933 {
934         int res;
935         ast_pthread_mutex_lock(&usecnt_lock);
936         res = usecnt;
937         ast_pthread_mutex_unlock(&usecnt_lock);
938         return res;
939 }
940
941 char *key()
942 {
943         return ASTERISK_GPL_KEY;
944 }
945
946 char *description()
947 {
948         return desc;
949 }
950