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