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