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