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