Fixed ackcall (once again, this time differently) in chan_agent
[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 <asterisk/causes.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 after agent logged in/off\n";
68
69 static char *descrip2 =
70 "  AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
71 "Asks the agent to login to the system with callback.\n"
72 "The agent's callback extension is called (optionally with the specified\n"
73 "context). \n"
74 "The option string may contain zero or more of the following characters:\n"
75 "      's' -- silent login - do not announce the login ok segment agent logged in/off\n";
76  
77
78
79 static char *descrip3 =
80 "  AgentMonitorOutgoing([options]):\n"
81 "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"
82 "       'd' - make the app return -1 if there is an error condition and there is no extension n+101\n"
83 "       'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
84 "       '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";
85
86 static char mandescr_agents[] =
87 "Description: Will list info about all possible agents.\n"
88 "Variables: NONE\n";
89
90 static char moh[80] = "default";
91
92 #define AST_MAX_AGENT   80              /* Agent ID or Password max length */
93 #define AST_MAX_BUF     256
94 #define AST_MAX_FILENAME_LEN    256
95
96 static int capability = -1;
97
98 static unsigned int group;
99 static int autologoff;
100 static int wrapuptime;
101 static int ackcall;
102
103 static int maxlogintries = 3;
104 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
105
106 static int usecnt =0;
107 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
108
109 /* Protect the interface list (of sip_pvt's) */
110 AST_MUTEX_DEFINE_STATIC(agentlock);
111
112 static int recordagentcalls = 0;
113 static char recordformat[AST_MAX_BUF] = "";
114 static char recordformatext[AST_MAX_BUF] = "";
115 static int createlink = 0;
116 static char urlprefix[AST_MAX_BUF] = "";
117 static char savecallsin[AST_MAX_BUF] = "";
118 static int updatecdr = 0;
119 static char beep[AST_MAX_BUF] = "beep";
120
121 #define GETAGENTBYCALLERID      "AGENTBYCALLERID"
122
123 static struct agent_pvt {
124         ast_mutex_t lock;                               /* Channel private lock */
125         int dead;                                                       /* Poised for destruction? */
126         int pending;                                            /* Not a real agent -- just pending a match */
127         int abouttograb;                                        /* About to grab */
128         int autologoff;                                 /* Auto timeout time */
129         int ackcall;                                    /* ackcall */
130         time_t loginstart;                                      /* When agent first logged in (0 when logged off) */
131         time_t start;                                           /* When call started */
132         struct timeval lastdisc;                        /* When last disconnected */
133         int wrapuptime;                                         /* Wrapup time in ms */
134         unsigned int group;                                     /* Group memberships */
135         int acknowledged;                                       /* Acknowledged */
136         char moh[80];                                           /* Which music on hold */
137         char agent[AST_MAX_AGENT];                      /* Agent ID */
138         char password[AST_MAX_AGENT];           /* Password for Agent login */
139         char name[AST_MAX_AGENT];
140         ast_mutex_t app_lock;                   /* Synchronization between owning applications */
141         volatile pthread_t owning_app;          /* Owning application thread id */
142         volatile int app_sleep_cond;            /* Sleep condition for the login app */
143         struct ast_channel *owner;                      /* Agent */
144         char loginchan[80];
145         struct ast_channel *chan;                       /* Channel we use */
146         struct agent_pvt *next;                         /* Agent */
147 } *agents = NULL;
148
149 #define CHECK_FORMATS(ast, p) do { \
150         if (p->chan) {\
151                 if (ast->nativeformats != p->chan->nativeformats) { \
152                         ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
153                         /* Native formats changed, reset things */ \
154                         ast->nativeformats = p->chan->nativeformats; \
155                         ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
156                         ast_set_read_format(ast, ast->readformat); \
157                         ast_set_write_format(ast, ast->writeformat); \
158                 } \
159                 if (p->chan->readformat != ast->pvt->rawreadformat)  \
160                         ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
161                 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
162                         ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
163         } \
164 } while(0)
165
166 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
167    properly for a timingfd XXX This might need more work if agents were logged in as agents or other
168    totally impractical combinations XXX */
169
170 #define CLEANUP(ast, p) do { \
171         int x; \
172         if (p->chan) { \
173                 for (x=0;x<AST_MAX_FDS;x++) {\
174                         if (x != AST_MAX_FDS - 2) \
175                                 ast->fds[x] = p->chan->fds[x]; \
176                 } \
177                 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
178         } \
179 } while(0)
180
181
182 static void agent_unlink(struct agent_pvt *agent)
183 {
184         struct agent_pvt *p, *prev;
185         prev = NULL;
186         p = agents;
187         while(p) {
188                 if (p == agent) {
189                         if (prev)
190                                 prev->next = agent->next;
191                         else
192                                 agents = agent->next;
193                         break;
194                 }
195                 prev = p;
196                 p = p->next;
197         }
198 }
199
200 static struct agent_pvt *add_agent(char *agent, int pending)
201 {
202         char tmp[AST_MAX_BUF] = "";
203         char *password=NULL, *name=NULL;
204         struct agent_pvt *p, *prev;
205         
206         strncpy(tmp, agent, sizeof(tmp) - 1);
207         if ((password = strchr(tmp, ','))) {
208                 *password = '\0';
209                 password++;
210                 while (*password < 33) password++;
211         }
212         if (password && (name = strchr(password, ','))) {
213                 *name = '\0';
214                 name++;
215                 while (*name < 33) name++; 
216         }
217         prev=NULL;
218         p = agents;
219         while(p) {
220                 if (!pending && !strcmp(p->agent, tmp))
221                         break;
222                 prev = p;
223                 p = p->next;
224         }
225         if (!p) {
226                 p = malloc(sizeof(struct agent_pvt));
227                 if (p) {
228                         memset(p, 0, sizeof(struct agent_pvt));
229                         strncpy(p->agent, tmp, sizeof(p->agent) -1);
230                         ast_mutex_init(&p->lock);
231                         ast_mutex_init(&p->app_lock);
232                         p->owning_app = (pthread_t) -1;
233                         p->app_sleep_cond = 1;
234                         p->group = group;
235                         p->pending = pending;
236                         p->next = NULL;
237                         if (prev)
238                                 prev->next = p;
239                         else
240                                 agents = p;
241                         
242                 }
243         }
244         if (!p)
245                 return NULL;
246         strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
247         strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
248         strncpy(p->moh, moh, sizeof(p->moh) - 1);
249         p->ackcall = ackcall;
250         p->autologoff = autologoff;
251         p->wrapuptime = wrapuptime;
252         if (pending)
253                 p->dead = 1;
254         else
255                 p->dead = 0;
256         return p;
257 }
258
259 static int agent_cleanup(struct agent_pvt *p)
260 {
261         struct ast_channel *chan = p->owner;
262         p->owner = NULL;
263         chan->pvt->pvt = NULL;
264         p->app_sleep_cond = 1;
265         /* Release ownership of the agent to other threads (presumably running the login app). */
266         ast_mutex_unlock(&p->app_lock);
267         if (chan)
268                 ast_channel_free(chan);
269         if (p->dead) {
270                 ast_mutex_destroy(&p->lock);
271                 ast_mutex_destroy(&p->app_lock);
272                 free(p);
273         }
274         return 0;
275 }
276
277 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
278
279 static int agent_answer(struct ast_channel *ast)
280 {
281         ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
282         return -1;
283 }
284
285 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
286 {
287         char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
288         char filename[AST_MAX_BUF];
289         int res = -1;
290         if (!p)
291                 return -1;
292         if (!ast->monitor) {
293                 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
294                 /* substitute . for - */
295                 if ((pointer = strchr(filename, '.')))
296                         *pointer = '-';
297                 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
298                 ast_monitor_start(ast, recordformat, tmp, needlock);
299                 ast_monitor_setjoinfiles(ast, 1);
300                 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
301 #if 0
302                 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
303 #endif
304                 if (!ast->cdr)
305                         ast->cdr = ast_cdr_alloc();
306                 ast_cdr_setuserfield(ast, tmp2);
307                 res = 0;
308         } else
309                 ast_log(LOG_ERROR, "Recording already started on that call.\n");
310         return res;
311 }
312
313 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
314 {
315         return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
316 }
317
318 static struct ast_frame  *agent_read(struct ast_channel *ast)
319 {
320         struct agent_pvt *p = ast->pvt->pvt;
321         struct ast_frame *f = NULL;
322         static struct ast_frame null_frame = { AST_FRAME_NULL, };
323         static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
324         ast_mutex_lock(&p->lock); 
325         CHECK_FORMATS(ast, p);
326         if (p->chan) {
327                 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
328                 if (ast->fdno == AST_MAX_FDS - 3)
329                         p->chan->fdno = AST_MAX_FDS - 2;
330                 else
331                         p->chan->fdno = ast->fdno;
332                 f = ast_read(p->chan);
333         } else
334                 f = &null_frame;
335         if (!f) {
336                 /* If there's a channel, hang it up  (if it's on a callback) make it NULL */
337                 if (p->chan) {
338                         /* Note that we don't hangup if it's not a callback because Asterisk will do it
339                            for us when the PBX instance that called login finishes */
340                         if (!ast_strlen_zero(p->loginchan)) {
341                                 p->chan->_bridge = NULL;
342                                 ast_hangup(p->chan);
343                                 if (p->wrapuptime) {
344                                         gettimeofday(&p->lastdisc, NULL);
345                                         p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
346                                         if (p->lastdisc.tv_usec > 1000000) {
347                                                 p->lastdisc.tv_usec -= 1000000;
348                                                 p->lastdisc.tv_sec++;
349                                         }
350                                         p->lastdisc.tv_sec += (p->wrapuptime / 1000);
351                                 }
352                         }
353                         p->chan = NULL;
354                         p->acknowledged = 0;
355                 }
356         }
357         if ((p->chan && (p->chan->_state != AST_STATE_UP)) && f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
358 /* TC */
359                 if (p->ackcall) {
360                         if (option_verbose > 2)
361                                 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
362                         /* Don't pass answer along */
363                         ast_frfree(f);
364                         f = &null_frame;
365                 }
366         else {
367                         p->acknowledged = 1;
368                         f = &answer_frame;
369                         if (p->chan)
370                                 p->chan->_bridge = ast;
371
372         }
373         }
374         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
375                 if (!p->acknowledged) {
376                         if (option_verbose > 2)
377                                 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
378                         p->acknowledged = 1;
379                         ast_frfree(f);
380                         f = &answer_frame;
381                         if (p->chan)
382                                 p->chan->_bridge = ast;
383                 }
384         }
385         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
386                 /* * terminates call */
387                 ast_frfree(f);
388                 f = NULL;
389         }
390         CLEANUP(ast,p);
391         ast_mutex_unlock(&p->lock);
392         if (recordagentcalls && f == &answer_frame)
393                 agent_start_monitoring(ast,0);
394         return f;
395 }
396
397 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
398 {
399         struct agent_pvt *p = ast->pvt->pvt;
400         int res = -1;
401         CHECK_FORMATS(ast, p);
402         ast_mutex_lock(&p->lock);
403         if (p->chan) {
404                 if ((f->frametype != AST_FRAME_VOICE) ||
405                         (f->subclass == p->chan->writeformat)) {
406                         res = ast_write(p->chan, f);
407                 } else {
408                         ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
409                         res = 0;
410                 }
411         } else
412                 res = 0;
413         CLEANUP(ast, p);
414         ast_mutex_unlock(&p->lock);
415         return res;
416 }
417
418 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
419 {
420         struct agent_pvt *p = newchan->pvt->pvt;
421         ast_mutex_lock(&p->lock);
422         if (p->owner != oldchan) {
423                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
424                 ast_mutex_unlock(&p->lock);
425                 return -1;
426         }
427         p->owner = newchan;
428         ast_mutex_unlock(&p->lock);
429         return 0;
430 }
431
432 static int agent_indicate(struct ast_channel *ast, int condition)
433 {
434         struct agent_pvt *p = ast->pvt->pvt;
435         int res = -1;
436         ast_mutex_lock(&p->lock);
437         if (p->chan)
438                 res = ast_indicate(p->chan, condition);
439         else
440                 res = 0;
441         ast_mutex_unlock(&p->lock);
442         return res;
443 }
444
445 static int agent_digit(struct ast_channel *ast, char digit)
446 {
447         struct agent_pvt *p = ast->pvt->pvt;
448         int res = -1;
449         ast_mutex_lock(&p->lock);
450         if (p->chan)
451                 res = p->chan->pvt->send_digit(p->chan, digit);
452         else
453                 res = 0;
454         ast_mutex_unlock(&p->lock);
455         return res;
456 }
457
458 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
459 {
460         struct agent_pvt *p = ast->pvt->pvt;
461         int res = -1;
462         ast_mutex_lock(&p->lock);
463         p->acknowledged = 0;
464         if (!p->chan) {
465                 if (p->pending) {
466                         ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
467                         ast_setstate(ast, AST_STATE_DIALING);
468                         res = 0;
469                 } else {
470                         ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
471                         res = -1;
472                 }
473                 ast_mutex_unlock(&p->lock);
474                 return res;
475         } else if (!ast_strlen_zero(p->loginchan)) {
476                 time(&p->start);
477                 /* Call on this agent */
478                 if (option_verbose > 2)
479                         ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
480                 if (p->chan->cid.cid_num)
481                         free(p->chan->cid.cid_num);
482                 if (ast->cid.cid_num)
483                         p->chan->cid.cid_num = strdup(ast->cid.cid_num);
484                 else
485                         p->chan->cid.cid_num = NULL;
486                 if (p->chan->cid.cid_name)
487                         free(p->chan->cid.cid_name);
488                 if (ast->cid.cid_name)
489                         p->chan->cid.cid_name = strdup(ast->cid.cid_name);
490                 else
491                         p->chan->cid.cid_name = NULL;
492                 res = ast_call(p->chan, p->loginchan, 0);
493                 CLEANUP(ast,p);
494                 ast_mutex_unlock(&p->lock);
495                 return res;
496         }
497         ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
498         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
499         res = ast_streamfile(p->chan, beep, p->chan->language);
500         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
501         if (!res) {
502                 res = ast_waitstream(p->chan, "");
503                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
504         }
505         if (!res) {
506                 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
507                 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
508                 if (res)
509                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
510         } else {
511                 /* Agent hung-up */
512                 p->chan = NULL;
513         }
514
515         if (!res) {
516                 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
517                 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
518                 if (res)
519                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
520         }
521         if( !res )
522         {
523                 /* Call is immediately up, or might need ack */
524                 if (p->ackcall > 1)
525                         ast_setstate(ast, AST_STATE_RINGING);
526                 else {
527                         ast_setstate(ast, AST_STATE_UP);
528                         if (recordagentcalls)
529                                 agent_start_monitoring(ast,0);
530                         p->acknowledged = 1;
531                 }
532                 res = 0;
533         }
534         CLEANUP(ast,p);
535         ast_mutex_unlock(&p->lock);
536         return res;
537 }
538
539 static int agent_hangup(struct ast_channel *ast)
540 {
541         struct agent_pvt *p = ast->pvt->pvt;
542         int howlong = 0;
543         ast_mutex_lock(&p->lock);
544         p->owner = NULL;
545         ast->pvt->pvt = NULL;
546         p->app_sleep_cond = 1;
547         p->acknowledged = 0;
548
549         /* if they really are hung up then set start to 0 so the test
550          * later if we're called on an already downed channel
551          * doesn't cause an agent to be logged out like when
552          * agent_request() is followed immediately by agent_hangup()
553          * as in apps/app_chanisavail.c:chanavail_exec()
554          */
555
556         ast_mutex_lock(&usecnt_lock);
557         usecnt--;
558         ast_mutex_unlock(&usecnt_lock);
559
560         ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
561         if (p->start && (ast->_state != AST_STATE_UP)) {
562                 howlong = time(NULL) - p->start;
563                 p->start = 0;
564         } else if (ast->_state == AST_STATE_RESERVED) {
565                 howlong = 0;
566         } else
567                 p->start = 0; 
568         if (p->chan) {
569                 /* If they're dead, go ahead and hang up on the agent now */
570                 if (!ast_strlen_zero(p->loginchan)) {
571                         /* Store last disconnect time */
572                         if (p->wrapuptime) {
573                                 gettimeofday(&p->lastdisc, NULL);
574                                 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
575                                 if (p->lastdisc.tv_usec >= 1000000) {
576                                         p->lastdisc.tv_usec -= 1000000;
577                                         p->lastdisc.tv_sec++;
578                                 }
579                                 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
580                         } else
581                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
582                         if (p->chan) {
583                                 /* Recognize the hangup and pass it along immediately */
584                                 ast_hangup(p->chan);
585                                 p->chan = NULL;
586                         }
587                         ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
588                         if (howlong  && p->autologoff && (howlong > p->autologoff)) {
589                                 char agent[AST_MAX_AGENT] = "";
590                                 long logintime = time(NULL) - p->loginstart;
591                                 p->loginstart = 0;
592                                 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
593                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
594                                         "Agent: %s\r\n"
595                                         "Loginchan: %s\r\n"
596                                         "Logintime: %ld\r\n"
597                                         "Reason: Autologoff\r\n"
598                                         "Uniqueid: %s\r\n",
599                                         p->agent, p->loginchan, logintime, ast->uniqueid);
600                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
601                                 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
602                                 p->loginchan[0] = '\0';
603                             ast_device_state_changed("Agent/%s", p->agent);
604                         }
605                 } else if (p->dead) {
606                         ast_mutex_lock(&p->chan->lock);
607                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
608                         ast_mutex_unlock(&p->chan->lock);
609                 } else {
610                         ast_mutex_lock(&p->chan->lock);
611                         ast_moh_start(p->chan, p->moh);
612                         ast_mutex_unlock(&p->chan->lock);
613                 }
614         }
615 #if 0
616                 ast_mutex_unlock(&p->lock);
617                 /* Release ownership of the agent to other threads (presumably running the login app). */
618                 ast_mutex_unlock(&p->app_lock);
619         } else if (p->dead) {
620                 /* Go ahead and lose it */
621                 ast_mutex_unlock(&p->lock);
622                 /* Release ownership of the agent to other threads (presumably running the login app). */
623                 ast_mutex_unlock(&p->app_lock);
624         } else {
625                 ast_mutex_unlock(&p->lock);
626                 /* Release ownership of the agent to other threads (presumably running the login app). */
627                 ast_mutex_unlock(&p->app_lock);
628         }
629 #endif  
630         ast_mutex_unlock(&p->lock);
631
632         if (p->pending) {
633                 ast_mutex_lock(&agentlock);
634                 agent_unlink(p);
635                 ast_mutex_unlock(&agentlock);
636         }
637         if (p->abouttograb) {
638                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
639                    kill it later */
640                 p->abouttograb = 0;
641         } else if (p->dead) {
642                 ast_mutex_destroy(&p->lock);
643                 ast_mutex_destroy(&p->app_lock);
644                 free(p);
645         } else {
646                 if (p->chan) {
647                         /* Not dead -- check availability now */
648                         ast_mutex_lock(&p->lock);
649                         /* Store last disconnect time */
650                         gettimeofday(&p->lastdisc, NULL);
651                         ast_mutex_unlock(&p->lock);
652                 }
653                 /* Release ownership of the agent to other threads (presumably running the login app). */
654                 ast_mutex_unlock(&p->app_lock);
655         }
656         return 0;
657 }
658
659 static int agent_cont_sleep( void *data )
660 {
661         struct agent_pvt *p;
662         struct timeval tv;
663         int res;
664
665         p = (struct agent_pvt *)data;
666
667         ast_mutex_lock(&p->lock);
668         res = p->app_sleep_cond;
669         if (p->lastdisc.tv_sec) {
670                 gettimeofday(&tv, NULL);
671                 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
672                         (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) 
673                         res = 1;
674         }
675         ast_mutex_unlock(&p->lock);
676 #if 0
677         if( !res )
678                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
679 #endif          
680         return res;
681 }
682
683 static int agent_ack_sleep( void *data )
684 {
685         struct agent_pvt *p;
686         int res=0;
687         int to = 1000;
688         struct ast_frame *f;
689
690         /* Wait a second and look for something */
691
692         p = (struct agent_pvt *)data;
693         if (p->chan) {
694                 for(;;) {
695                         to = ast_waitfor(p->chan, to);
696                         if (to < 0) {
697                                 res = -1;
698                                 break;
699                         }
700                         if (!to) {
701                                 res = 0;
702                                 break;
703                         }
704                         f = ast_read(p->chan);
705                         if (!f) {
706                                 res = -1;
707                                 break;
708                         }
709                         if (f->frametype == AST_FRAME_DTMF)
710                                 res = f->subclass;
711                         else
712                                 res = 0;
713                         ast_frfree(f);
714                         ast_mutex_lock(&p->lock);
715                         if (!p->app_sleep_cond) {
716                                 ast_mutex_unlock(&p->lock);
717                                 res = 0;
718                                 break;
719                         } else if (res == '#') {
720                                 ast_mutex_unlock(&p->lock);
721                                 res = 1;
722                                 break;
723                         }
724                         ast_mutex_unlock(&p->lock);
725                         res = 0;
726                 }
727         } else
728                 res = -1;
729         return res;
730 }
731
732 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
733 {
734         struct agent_pvt *p;
735         struct ast_channel *ret=NULL;
736
737         p = bridge->pvt->pvt;
738         if (chan == p->chan)
739                 ret = bridge->_bridge;
740         else if (chan == bridge->_bridge)
741                 ret = p->chan;
742         return NULL;
743 }
744
745 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
746 {
747         struct ast_channel *tmp;
748         struct ast_frame null_frame = { AST_FRAME_NULL };
749 #if 0
750         if (!p->chan) {
751                 ast_log(LOG_WARNING, "No channel? :(\n");
752                 return NULL;
753         }
754 #endif  
755         tmp = ast_channel_alloc(0);
756         if (tmp) {
757                 if (p->chan) {
758                         tmp->nativeformats = p->chan->nativeformats;
759                         tmp->writeformat = p->chan->writeformat;
760                         tmp->pvt->rawwriteformat = p->chan->writeformat;
761                         tmp->readformat = p->chan->readformat;
762                         tmp->pvt->rawreadformat = p->chan->readformat;
763                         strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
764                         strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
765                         strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
766                 } else {
767                         tmp->nativeformats = AST_FORMAT_SLINEAR;
768                         tmp->writeformat = AST_FORMAT_SLINEAR;
769                         tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
770                         tmp->readformat = AST_FORMAT_SLINEAR;
771                         tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
772                 }
773                 if (p->pending)
774                         snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
775                 else
776                         snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
777                 tmp->type = type;
778                 ast_setstate(tmp, state);
779                 tmp->pvt->pvt = p;
780                 tmp->pvt->send_digit = agent_digit;
781                 tmp->pvt->call = agent_call;
782                 tmp->pvt->hangup = agent_hangup;
783                 tmp->pvt->answer = agent_answer;
784                 tmp->pvt->read = agent_read;
785                 tmp->pvt->write = agent_write;
786                 tmp->pvt->exception = agent_read;
787                 tmp->pvt->indicate = agent_indicate;
788                 tmp->pvt->fixup = agent_fixup;
789                 tmp->pvt->bridged_channel = agent_bridgedchannel;
790                 p->owner = tmp;
791                 ast_mutex_lock(&usecnt_lock);
792                 usecnt++;
793                 ast_mutex_unlock(&usecnt_lock);
794                 ast_update_use_count();
795                 tmp->priority = 1;
796                 /* Wake up and wait for other applications (by definition the login app)
797                  * to release this channel). Takes ownership of the agent channel
798                  * to this thread only.
799                  * For signalling the other thread, ast_queue_frame is used until we
800                  * can safely use signals for this purpose. The pselect() needs to be
801                  * implemented in the kernel for this.
802                  */
803                 p->app_sleep_cond = 0;
804                 if( ast_mutex_trylock(&p->app_lock) )
805                 {
806                         if (p->chan) {
807                                 ast_queue_frame(p->chan, &null_frame);
808                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
809                                 ast_mutex_lock(&p->app_lock);
810                                 ast_mutex_lock(&p->lock);
811                         }
812                         if( !p->chan )
813                         {
814                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
815                                 p->owner = NULL;
816                                 tmp->pvt->pvt = NULL;
817                                 p->app_sleep_cond = 1;
818                                 ast_channel_free( tmp );
819                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
820                                 ast_mutex_unlock(&p->app_lock);
821                                 return NULL;
822                         }
823                 }
824                 p->owning_app = pthread_self();
825                 /* After the above step, there should not be any blockers. */
826                 if (p->chan) {
827                         if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
828                                 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
829                                 CRASH;
830                         }
831                         ast_moh_stop(p->chan);
832                 }
833         } else
834                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
835         return tmp;
836 }
837
838
839 static int read_agent_config(void)
840 {
841         struct ast_config *cfg;
842         struct ast_variable *v;
843         struct agent_pvt *p, *pl, *pn;
844         group = 0;
845         autologoff = 0;
846         wrapuptime = 0;
847         ackcall = 1;
848         cfg = ast_load(config);
849         if (!cfg) {
850                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
851                 return 0;
852         }
853         ast_mutex_lock(&agentlock);
854         p = agents;
855         while(p) {
856                 p->dead = 1;
857                 p = p->next;
858         }
859         strncpy(moh, "default", sizeof(moh) - 1);
860         /* set the default recording values */
861         recordagentcalls = 0;
862         createlink = 0;
863         strncpy(recordformat, "wav", sizeof(recordformat) - 1);
864         strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
865         urlprefix[0] = '\0';
866         savecallsin[0] = '\0';
867
868         v = ast_variable_browse(cfg, "agents");
869         while(v) {
870                 /* Create the interface list */
871                 if (!strcasecmp(v->name, "agent")) {
872                         add_agent(v->value, 0);
873                 } else if (!strcasecmp(v->name, "group")) {
874                         group = ast_get_group(v->value);
875                 } else if (!strcasecmp(v->name, "autologoff")) {
876                         autologoff = atoi(v->value);
877                         if (autologoff < 0)
878                                 autologoff = 0;
879                 } else if (!strcasecmp(v->name, "ackcall")) {
880                         if (!strcasecmp(v->value, "always"))
881                                 ackcall = 2;
882                         else if (ast_true(v->value))
883                 ackcall = 1;
884                         else
885                                 ackcall = 0;
886                 } else if (!strcasecmp(v->name, "wrapuptime")) {
887                         wrapuptime = atoi(v->value);
888                         if (wrapuptime < 0)
889                                 wrapuptime = 0;
890                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
891                         maxlogintries = atoi(v->value);
892                         if (maxlogintries < 0)
893                                 maxlogintries = 0;
894                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
895                         strcpy(agentgoodbye,v->value);
896                 } else if (!strcasecmp(v->name, "musiconhold")) {
897                         strncpy(moh, v->value, sizeof(moh) - 1);
898                 } else if (!strcasecmp(v->name, "updatecdr")) {
899                         if (ast_true(v->value))
900                                 updatecdr = 1;
901                         else
902                                 updatecdr = 0;
903                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
904                         recordagentcalls = ast_true(v->value);
905                 } else if (!strcasecmp(v->name, "createlink")) {
906                         createlink = ast_true(v->value);
907                 } else if (!strcasecmp(v->name, "recordformat")) {
908                         strncpy(recordformat, v->value, sizeof(recordformat) - 1);
909                         if (!strcasecmp(v->value, "wav49"))
910                                 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
911                         else
912                                 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
913                 } else if (!strcasecmp(v->name, "urlprefix")) {
914                         strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
915                         if (urlprefix[strlen(urlprefix) - 1] != '/')
916                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
917                 } else if (!strcasecmp(v->name, "savecallsin")) {
918                         if (v->value[0] == '/')
919                                 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
920                         else
921                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
922                         if (savecallsin[strlen(savecallsin) - 1] != '/')
923                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
924                 } else if (!strcasecmp(v->name, "custom_beep")) {
925                         strncpy(beep, v->value, sizeof(beep) - 1);
926                 }
927                 v = v->next;
928         }
929         p = agents;
930         pl = NULL;
931         while(p) {
932                 pn = p->next;
933                 if (p->dead) {
934                         /* Unlink */
935                         if (pl)
936                                 pl->next = p->next;
937                         else
938                                 agents = p->next;
939                         /* Destroy if  appropriate */
940                         if (!p->owner) {
941                                 if (!p->chan) {
942                                         ast_mutex_destroy(&p->lock);
943                                         ast_mutex_destroy(&p->app_lock);
944                                         free(p);
945                                 } else {
946                                         /* Cause them to hang up */
947                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
948                                 }
949                         }
950                 } else
951                         pl = p;
952                 p = pn;
953         }
954         ast_mutex_unlock(&agentlock);
955         ast_destroy(cfg);
956         return 0;
957 }
958
959 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
960 {
961         struct ast_channel *chan=NULL, *parent=NULL;
962         struct agent_pvt *p;
963         int res;
964         ast_log(LOG_DEBUG, "Checking 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 winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
976                         /* We found a pending call, time to merge */
977                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
978                         parent = p->owner;
979                         p->abouttograb = 1;
980                         ast_mutex_unlock(&p->lock);
981                         break;
982                 }
983                 ast_mutex_unlock(&p->lock);
984                 p = p->next;
985         }
986         if (needlock)
987                 ast_mutex_unlock(&agentlock);
988         if (parent && chan)  {
989                 if (newlyavailable->ackcall > 1) {
990                         /* Don't do beep here */
991                         res = 0;
992                 } else {
993                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
994                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
995                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
996                         if (!res) {
997                                 res = ast_waitstream(newlyavailable->chan, "");
998                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
999                         }
1000                 }
1001                 if (!res) {
1002                         /* Note -- parent may have disappeared */
1003                         if (p->abouttograb) {
1004                                 newlyavailable->acknowledged = 1;
1005                                 ast_setstate(parent, AST_STATE_UP);
1006                                 ast_setstate(chan, AST_STATE_UP);
1007                                 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1008                                 /* Go ahead and mark the channel as a zombie so that masquerade will
1009                                    destroy it for us, and we need not call ast_hangup */
1010                                 ast_mutex_lock(&parent->lock);
1011                                 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1012                                 ast_channel_masquerade(parent, chan);
1013                                 ast_mutex_unlock(&parent->lock);
1014                                 p->abouttograb = 0;
1015                         } else {
1016                                 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1017                                 agent_cleanup(newlyavailable);
1018                         }
1019                 } else {
1020                         ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
1021                         agent_cleanup(newlyavailable);
1022                 }
1023         }
1024         return 0;
1025 }
1026
1027 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1028 {
1029         struct agent_pvt *p;
1030         int res=0;
1031         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1032         if (needlock)
1033                 ast_mutex_lock(&agentlock);
1034         p = agents;
1035         while(p) {
1036                 if (p == newlyavailable) {
1037                         p = p->next;
1038                         continue;
1039                 }
1040                 ast_mutex_lock(&p->lock);
1041                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1042                         ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1043                         ast_mutex_unlock(&p->lock);
1044                         break;
1045                 }
1046                 ast_mutex_unlock(&p->lock);
1047                 p = p->next;
1048         }
1049         if (needlock)
1050                 ast_mutex_unlock(&agentlock);
1051         if (p) {
1052                 ast_mutex_unlock(&newlyavailable->lock);
1053                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1054                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1055                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1056                 if (!res) {
1057                         res = ast_waitstream(newlyavailable->chan, "");
1058                         ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1059                 }
1060                 ast_mutex_lock(&newlyavailable->lock);
1061         }
1062         return res;
1063 }
1064
1065 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1066 {
1067         struct agent_pvt *p;
1068         struct ast_channel *chan = NULL;
1069         char *s;
1070         unsigned int groupmatch;
1071         int waitforagent=0;
1072         int hasagent = 0;
1073         struct timeval tv;
1074         s = data;
1075         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1076                 groupmatch = (1 << groupmatch);
1077         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1078                 groupmatch = (1 << groupmatch);
1079                 waitforagent = 1;
1080         } else {
1081                 groupmatch = 0;
1082         }
1083
1084         /* Check actual logged in agents first */
1085         ast_mutex_lock(&agentlock);
1086         p = agents;
1087         while(p) {
1088                 ast_mutex_lock(&p->lock);
1089                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1090                                 ast_strlen_zero(p->loginchan)) {
1091                         if (p->chan)
1092                                 hasagent++;
1093                         if (!p->lastdisc.tv_sec) {
1094                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1095                                 if (!p->owner && p->chan) {
1096                                         /* Fixed agent */
1097                                         chan = agent_new(p, AST_STATE_DOWN);
1098                                 }
1099                                 if (chan) {
1100                                         ast_mutex_unlock(&p->lock);
1101                                         break;
1102                                 }
1103                         }
1104                 }
1105                 ast_mutex_unlock(&p->lock);
1106                 p = p->next;
1107         }
1108         if (!p) {
1109                 p = agents;
1110                 while(p) {
1111                         ast_mutex_lock(&p->lock);
1112                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1113                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1114                                         hasagent++;
1115                                 gettimeofday(&tv, NULL);
1116 #if 0
1117                                 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1118 #endif
1119                                 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1120                                         memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1121                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1122                                         if (!p->owner && p->chan) {
1123                                                 /* Could still get a fixed agent */
1124                                                 chan = agent_new(p, AST_STATE_DOWN);
1125                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1126                                                 /* Adjustable agent */
1127                                                 p->chan = ast_request("Local", format, p->loginchan, cause);
1128                                                 if (p->chan)
1129                                                         chan = agent_new(p, AST_STATE_DOWN);
1130                                         }
1131                                         if (chan) {
1132                                                 ast_mutex_unlock(&p->lock);
1133                                                 break;
1134                                         }
1135                                 }
1136                         }
1137                         ast_mutex_unlock(&p->lock);
1138                         p = p->next;
1139                 }
1140         }
1141
1142         if (!chan && waitforagent) {
1143                 /* No agent available -- but we're requesting to wait for one.
1144                    Allocate a place holder */
1145                 if (hasagent) {
1146                         ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1147                         p = add_agent(data, 1);
1148                         p->group = groupmatch;
1149                         chan = agent_new(p, AST_STATE_DOWN);
1150                         if (!chan) {
1151                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1152                         }
1153                 } else
1154                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1155         }
1156         if (hasagent)
1157                 *cause = AST_CAUSE_BUSY;
1158         else
1159                 *cause = AST_CAUSE_UNREGISTERED;
1160         ast_mutex_unlock(&agentlock);
1161         return chan;
1162 }
1163
1164 static int powerof(unsigned int v)
1165 {
1166         int x;
1167         for (x=0;x<32;x++) {
1168                 if (v & (1 << x)) return x;
1169         }
1170         return 0;
1171 }
1172
1173 static int action_agents(struct mansession *s, struct message *m)
1174 {
1175        struct agent_pvt *p;
1176        char *username = NULL;
1177        char *loginChan = NULL;
1178        char *talkingtoChan = NULL;
1179        char *status = NULL;
1180        ast_mutex_lock(&agentlock);
1181        p = agents;
1182        while(p) {
1183                ast_mutex_lock(&p->lock);
1184
1185                /* Status Values:       AGENT_LOGGEDOFF - Agent isn't logged in
1186                                        AGENT_IDLE      - Agent is logged in, and waiting for call
1187                                        AGENT_ONCALL    - Agent is logged in, and on a call
1188                                        AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1189
1190                if(!ast_strlen_zero(p->name)) {
1191                        username = p->name;
1192                } else {
1193                        username = "None";
1194                }
1195
1196                /* Set a default status. It 'should' get changed. */
1197                status = "AGENT_UNKNOWN";
1198
1199                if(p->chan) {
1200                        loginChan = p->loginchan;
1201                        if(p->owner && p->owner->_bridge) {
1202                                talkingtoChan = p->chan->cid.cid_num;
1203                                status = "AGENT_ONCALL";
1204                        } else {
1205                                talkingtoChan = "n/a";
1206                                status = "AGENT_IDLE";
1207                        }
1208                } else if(!ast_strlen_zero(p->loginchan)) {
1209                        loginChan = p->loginchan;
1210                        talkingtoChan = "n/a";
1211                        status = "AGENT_IDLE";
1212                        if(p->acknowledged) {
1213                                sprintf(loginChan, " %s (Confirmed)", loginChan);
1214                        }
1215                } else {
1216                        loginChan = "n/a";
1217                        talkingtoChan = "n/a";
1218                        status = "AGENT_LOGGEDOFF";
1219                }
1220
1221                ast_cli(s->fd, "Event: Agents\r\n"
1222                                        "Agent: %s\r\n"
1223                                        "Name: %s\r\n"
1224                                        "Status: %s\r\n"
1225                                        "LoggedInChan: %s\r\n"
1226                                        "LoggedInTime: %ld\r\n"
1227                                        "TalkingTo: %s\r\n"
1228                                        "\r\n",
1229                                        p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1230                ast_mutex_unlock(&p->lock);
1231                p = p->next;
1232        }
1233        ast_mutex_unlock(&agentlock);
1234         return 0;
1235 }
1236
1237
1238 static int agents_show(int fd, int argc, char **argv)
1239 {
1240         struct agent_pvt *p;
1241         char username[AST_MAX_BUF];
1242         char location[AST_MAX_BUF] = "";
1243         char talkingto[AST_MAX_BUF] = "";
1244         char moh[AST_MAX_BUF];
1245
1246         if (argc != 2)
1247                 return RESULT_SHOWUSAGE;
1248         ast_mutex_lock(&agentlock);
1249         p = agents;
1250         while(p) {
1251                 ast_mutex_lock(&p->lock);
1252                 if (p->pending) {
1253                         if (p->group)
1254                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1255                         else
1256                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1257                 } else {
1258                         if (!ast_strlen_zero(p->name))
1259                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1260                         else
1261                                 username[0] = '\0';
1262                         if (p->chan) {
1263                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1264                                 if (p->owner && ast_bridged_channel(p->owner)) {
1265                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1266                                 } else {
1267                                         strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1268                                 }
1269                         } else if (!ast_strlen_zero(p->loginchan)) {
1270                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1271                                 talkingto[0] = '\0';
1272                                 if (p->acknowledged)
1273                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1274                         } else {
1275                                 strncpy(location, "not logged in", sizeof(location) - 1);
1276                                 talkingto[0] = '\0';
1277                         }
1278                         if (!ast_strlen_zero(p->moh))
1279                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1280                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1281                                         username, location, talkingto, moh);
1282                 }
1283                 ast_mutex_unlock(&p->lock);
1284                 p = p->next;
1285         }
1286         ast_mutex_unlock(&agentlock);
1287         return RESULT_SUCCESS;
1288 }
1289
1290 static char show_agents_usage[] = 
1291 "Usage: show agents\n"
1292 "       Provides summary information on agents.\n";
1293
1294 static struct ast_cli_entry cli_show_agents = {
1295         { "show", "agents", NULL }, agents_show, 
1296         "Show status of agents", show_agents_usage, NULL };
1297
1298 STANDARD_LOCAL_USER;
1299 LOCAL_USER_DECL;
1300
1301 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1302 {
1303         int res=0;
1304         int tries = 0;
1305         int max_login_tries = maxlogintries;
1306         struct agent_pvt *p;
1307         struct localuser *u;
1308         struct timeval tv;
1309         int login_state = 0;
1310         char user[AST_MAX_AGENT] = "";
1311         char pass[AST_MAX_AGENT];
1312         char agent[AST_MAX_AGENT] = "";
1313         char xpass[AST_MAX_AGENT] = "";
1314         char *errmsg;
1315         char info[512];
1316         char *opt_user = NULL;
1317         char *options = NULL;
1318         char option;
1319         char badoption[2];
1320         char *tmpoptions = NULL;
1321         char *context = NULL;
1322         char *exten = NULL;
1323         int play_announcement = 1;
1324         char agent_goodbye[AST_MAX_FILENAME_LEN];
1325         int update_cdr = updatecdr;
1326         char *filename = "agent-loginok";
1327         
1328         strcpy(agent_goodbye, agentgoodbye);
1329         LOCAL_USER_ADD(u);
1330
1331         /* Parse the arguments XXX Check for failure XXX */
1332         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1333         opt_user = info;
1334         /* Set Channel Specific Login Overrides */
1335         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1336                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1337                 if (max_login_tries < 0)
1338                         max_login_tries = 0;
1339                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1340                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1341         }
1342         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && strlen(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1343                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1344                         update_cdr = 1;
1345                 else
1346                         update_cdr = 0;
1347                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1348                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1349         }
1350         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && strlen(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1351                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1352                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1353                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1354         }
1355         /* End Channel Specific Login Overrides */
1356         /* Read command line options */
1357          if( opt_user ) {
1358                 options = strchr(opt_user, '|');
1359                 if (options) {
1360                         *options = '\0';
1361                         options++;
1362                         if (callbackmode) {
1363                                 context = strchr(options, '@');
1364                                 if (context) {
1365                                         *context = '\0';
1366                                         context++;
1367                                 }
1368                                 exten = options;
1369                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1370                                 if (!*exten)
1371                                         exten = NULL;
1372                         }
1373                 }
1374                 if (options) {
1375                         while (*options) {
1376                                 option = (char)options[0];
1377                                 if ((option >= 0) && (option <= '9'))
1378                                 {
1379                                         options++;
1380                                         continue;
1381                                 }
1382                                 if (option=='s')
1383                                         play_announcement = 0;
1384                                 else {
1385                                         badoption[0] = option;
1386                                         badoption[1] = '\0';
1387                                         tmpoptions=badoption;
1388                                         ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1389                                 }
1390                                 options++;
1391                         }
1392                 }
1393         }
1394         /* End command line options */
1395
1396         if (chan->_state != AST_STATE_UP)
1397                 res = ast_answer(chan);
1398         if (!res) {
1399                 if( opt_user && !ast_strlen_zero(opt_user))
1400                         strncpy( user, opt_user, AST_MAX_AGENT - 1);
1401                 else
1402                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1403         }
1404         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1405                 tries++;
1406                 /* Check for password */
1407                 ast_mutex_lock(&agentlock);
1408                 p = agents;
1409                 while(p) {
1410                         if (!strcmp(p->agent, user) && !p->pending)
1411                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1412                         p = p->next;
1413                 }
1414                 ast_mutex_unlock(&agentlock);
1415                 if (!res) {
1416                         if (!ast_strlen_zero(xpass))
1417                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1418                         else
1419                                 pass[0] = '\0';
1420                 }
1421                 errmsg = "agent-incorrect";
1422
1423 #if 0
1424                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1425 #endif          
1426
1427                 /* Check again for accuracy */
1428                 ast_mutex_lock(&agentlock);
1429                 p = agents;
1430                 while(p) {
1431                         ast_mutex_lock(&p->lock);
1432                         if (!strcmp(p->agent, user) &&
1433                                 !strcmp(p->password, pass) && !p->pending) {
1434                                         login_state = 1; /* Successful Login */
1435                                         /* Set Channel Specific Agent Overides */
1436                                         if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1437                                                 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1438                                                         p->ackcall = 2;
1439                                                 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1440                                                         p->ackcall = 1;
1441                                                 else
1442                                                         p->ackcall = 0;
1443                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1444                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1445                                         }
1446                                         if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1447                                                 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1448                                                 if (p->autologoff < 0)
1449                                                         p->autologoff = 0;
1450                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1451                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1452                                         }
1453                                         if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1454                                                 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1455                                                 if (p->wrapuptime < 0)
1456                                                         p->wrapuptime = 0;
1457                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1458                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1459                                         }
1460                                         /* End Channel Specific Agent Overides */
1461                                         if (!p->chan) {
1462                                                 char last_loginchan[80] = "";
1463                                                 long logintime;
1464                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1465
1466                                                 if (callbackmode) {
1467                                                         char tmpchan[AST_MAX_BUF] = "";
1468                                                         int pos = 0;
1469                                                         /* Retrieve login chan */
1470                                                         for (;;) {
1471                                                                 if (exten) {
1472                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1473                                                                         res = 0;
1474                                                                 } else
1475                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1476                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1477                                                                                         1, NULL))
1478                                                                         break;
1479                                                                 if (exten) {
1480                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1481                                                                         exten = NULL;
1482                                                                         pos = 0;
1483                                                                 } else {
1484                                                                         ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, context && !ast_strlen_zero(context) ? context : "default", p->agent);
1485                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1486                                                                         if (!res)
1487                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1488                                                                         if (res > 0) {
1489                                                                                 tmpchan[0] = res;
1490                                                                                 tmpchan[1] = '\0';
1491                                                                                 pos = 1;
1492                                                                         } else {
1493                                                                                 tmpchan[0] = '\0';
1494                                                                                 pos = 0;
1495                                                                         }
1496                                                                 }
1497                                                         }
1498                                                         exten = tmpchan;
1499                                                         if (!res) {
1500                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1501                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1502                                                                 else {
1503                                                                         strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1504                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1505                                                                 }
1506                                                                 if (ast_strlen_zero(p->loginchan)) {
1507                                                                         login_state = 2;
1508                                                                         filename = "agent-loggedoff";
1509                                                                 }
1510                                                                 p->acknowledged = 0;
1511                                                                 /* store/clear the global variable that stores agentid based on the callerid */
1512                                                                 if (chan->cid.cid_num) {
1513                                                                         char agentvar[AST_MAX_BUF];
1514                                                                         snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1515                                                                         if (ast_strlen_zero(p->loginchan))
1516                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1517                                                                         else
1518                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1519                                                                 }
1520                                                                 if(update_cdr && chan->cdr)
1521                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1522
1523                                                         }
1524                                                 } else {
1525                                                         p->loginchan[0] = '\0';
1526                                                         p->acknowledged = 0;
1527                                                 }
1528                                                 ast_mutex_unlock(&p->lock);
1529                                                 ast_mutex_unlock(&agentlock);
1530                                                 if( !res && play_announcement==1 )
1531                                                         res = ast_streamfile(chan, filename, chan->language);
1532                                                 if (!res)
1533                                                         ast_waitstream(chan, "");
1534                                                 ast_mutex_lock(&agentlock);
1535                                                 ast_mutex_lock(&p->lock);
1536                                                 if (!res) {
1537                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1538                                                         if (res)
1539                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1540                                                 }
1541                                                 if (!res) {
1542                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1543                                                         if (res)
1544                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1545                                                 }
1546                                                 /* Check once more just in case */
1547                                                 if (p->chan)
1548                                                         res = -1;
1549                                                 if (callbackmode && !res) {
1550                                                         /* Just say goodbye and be done with it */
1551                                                         if (!ast_strlen_zero(p->loginchan)) {
1552                                                                 if (p->loginstart == 0)
1553                                                                         time(&p->loginstart);
1554                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1555                                                                         "Agent: %s\r\n"
1556                                                                         "Loginchan: %s\r\n"
1557                                                                         "Uniqueid: %s\r\n",
1558                                                                         p->agent, p->loginchan, chan->uniqueid);
1559                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1560                                                                 if (option_verbose > 2)
1561                                                                         ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1562                                                             ast_device_state_changed("Agent/%s", p->agent);
1563                                                         } else {
1564                                                                 logintime = time(NULL) - p->loginstart;
1565                                                                 p->loginstart = 0;
1566                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1567                                                                         "Agent: %s\r\n"
1568                                                                         "Loginchan: %s\r\n"
1569                                                                         "Logintime: %ld\r\n"
1570                                                                         "Uniqueid: %s\r\n",
1571                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1572                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1573                                                                 if (option_verbose > 2)
1574                                                                         ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged out\n", p->agent);
1575                                                             ast_device_state_changed("Agent/%s", p->agent);
1576                                                         }
1577                                                         ast_mutex_unlock(&agentlock);
1578                                                         if (!res)
1579                                                                 res = ast_safe_sleep(chan, 500);
1580                                                         ast_mutex_unlock(&p->lock);
1581                                                 } else if (!res) {
1582 #ifdef HONOR_MUSIC_CLASS
1583                                                         /* check if the moh class was changed with setmusiconhold */
1584                                                         if (*(chan->musicclass))
1585                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1586 #endif                                                          
1587                                                         ast_moh_start(chan, p->moh);
1588                                                         if (p->loginstart == 0)
1589                                                                 time(&p->loginstart);
1590                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1591                                                                 "Agent: %s\r\n"
1592                                                                 "Channel: %s\r\n"
1593                                                                 "Uniqueid: %s\r\n",
1594                                                                 p->agent, chan->name, chan->uniqueid);
1595                                                         if (update_cdr && chan->cdr)
1596                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1597                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1598                                                         if (option_verbose > 2)
1599                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1600                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1601                                                         /* Login this channel and wait for it to
1602                                                            go away */
1603                                                         p->chan = chan;
1604                                                         if (p->ackcall > 1)
1605                                                                 check_beep(p, 0);
1606                                                         else
1607                                                                 check_availability(p, 0);
1608                                                         ast_mutex_unlock(&p->lock);
1609                                                         ast_mutex_unlock(&agentlock);
1610                                                     ast_device_state_changed("Agent/%s", p->agent);
1611                                                         while (res >= 0) {
1612                                                                 ast_mutex_lock(&p->lock);
1613                                                                 if (p->chan != chan)
1614                                                                         res = -1;
1615                                                                 ast_mutex_unlock(&p->lock);
1616                                                                 /* Yield here so other interested threads can kick in. */
1617                                                                 sched_yield();
1618                                                                 if (res)
1619                                                                         break;
1620
1621                                                                 ast_mutex_lock(&agentlock);
1622                                                                 ast_mutex_lock(&p->lock);
1623                                                                 if (p->lastdisc.tv_sec) {
1624                                                                         gettimeofday(&tv, NULL);
1625                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1626                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1627                                                                                         ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1628                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1629                                                                                 if (p->ackcall > 1)
1630                                                                                         check_beep(p, 0);
1631                                                                                 else
1632                                                                                         check_availability(p, 0);
1633                                                                         }
1634                                                                 }
1635                                                                 ast_mutex_unlock(&p->lock);
1636                                                                 ast_mutex_unlock(&agentlock);
1637                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1638                                                                 ast_mutex_lock( &p->app_lock );
1639                                                                 ast_mutex_lock(&p->lock);
1640                                                                 p->owning_app = pthread_self();
1641                                                                 ast_mutex_unlock(&p->lock);
1642                                                                 if (p->ackcall > 1) 
1643                                                                         res = agent_ack_sleep(p);
1644                                                                 else
1645                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1646                                                                                                         agent_cont_sleep, p );
1647                                                                 ast_mutex_unlock( &p->app_lock );
1648                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1649                                                                         ast_mutex_lock(&agentlock);
1650                                                                         ast_mutex_lock(&p->lock);
1651                                                                         check_availability(p, 0);
1652                                                                         ast_mutex_unlock(&p->lock);
1653                                                                         ast_mutex_unlock(&agentlock);
1654                                                                         res = 0;
1655                                                                 }
1656                                                                 sched_yield();
1657                                                         }
1658                                                         ast_mutex_lock(&p->lock);
1659                                                         if (res && p->owner) 
1660                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1661                                                         /* Log us off if appropriate */
1662                                                         if (p->chan == chan)
1663                                                                 p->chan = NULL;
1664                                                         p->acknowledged = 0;
1665                                                         logintime = time(NULL) - p->loginstart;
1666                                                         p->loginstart = 0;
1667                                                         ast_mutex_unlock(&p->lock);
1668                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1669                                                                 "Agent: %s\r\n"
1670                                                                 "Logintime: %ld\r\n"
1671                                                                 "Uniqueid: %s\r\n",
1672                                                                 p->agent, logintime, chan->uniqueid);
1673                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1674                                                         if (option_verbose > 2)
1675                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1676                                                         /* If there is no owner, go ahead and kill it now */
1677                                                     ast_device_state_changed("Agent/%s", p->agent);
1678                                                         if (p->dead && !p->owner) {
1679                                                                 ast_mutex_destroy(&p->lock);
1680                                                                 ast_mutex_destroy(&p->app_lock);
1681                                                                 free(p);
1682                                                         }
1683                                                 }
1684                                                 else {
1685                                                         ast_mutex_unlock(&p->lock);
1686                                                         p = NULL;
1687                                                 }
1688                                                 res = -1;
1689                                         } else {
1690                                                 ast_mutex_unlock(&p->lock);
1691                                                 errmsg = "agent-alreadyon";
1692                                                 p = NULL;
1693                                         }
1694                                         break;
1695                         }
1696                         ast_mutex_unlock(&p->lock);
1697                         p = p->next;
1698                 }
1699                 if (!p)
1700                         ast_mutex_unlock(&agentlock);
1701
1702                 if (!res && (max_login_tries==0 || tries < max_login_tries))
1703                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1704         }
1705                 
1706         LOCAL_USER_REMOVE(u);
1707         if (!res)
1708                 res = ast_safe_sleep(chan, 500);
1709
1710         /* AgentLogin() exit */
1711         if (!callbackmode) {
1712                 return -1;
1713         }
1714         /* AgentCallbackLogin() exit*/
1715         else {
1716                 /* Set variables */
1717                 if (login_state > 0) {
1718                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1719                         if (login_state==1) {
1720                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1721                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1722                         }
1723                         else {
1724                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1725                         }
1726                 }
1727                 else {
1728                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1729                 }
1730                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1731                         return 0;
1732                 /* Do we need to play agent-goodbye now that we will be hanging up? */
1733                 if (play_announcement==1) {
1734                         if (!res)
1735                                 res = ast_safe_sleep(chan, 1000);
1736                         res = ast_streamfile(chan, agent_goodbye, chan->language);
1737                         if (!res)
1738                                 res = ast_waitstream(chan, "");
1739                         if (!res)
1740                                 res = ast_safe_sleep(chan, 1000);
1741                 }
1742         }
1743         /* We should never get here if next priority exists when in callbackmode */
1744         return -1;
1745 }
1746
1747 static int login_exec(struct ast_channel *chan, void *data)
1748 {
1749         return __login_exec(chan, data, 0);
1750 }
1751
1752 static int callback_exec(struct ast_channel *chan, void *data)
1753 {
1754         return __login_exec(chan, data, 1);
1755 }
1756
1757 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1758 {
1759         int exitifnoagentid = 0;
1760         int nowarnings = 0;
1761         int changeoutgoing = 0;
1762         int res = 0;
1763         char agent[AST_MAX_AGENT], *tmp;
1764         if (data) {
1765                 if (strchr(data, 'd'))
1766                         exitifnoagentid = 1;
1767                 if (strchr(data, 'n'))
1768                         nowarnings = 1;
1769                 if (strchr(data, 'c'))
1770                         changeoutgoing = 1;
1771         }
1772         if (chan->cid.cid_num) {
1773                 char agentvar[AST_MAX_BUF];
1774                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1775                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1776                         struct agent_pvt *p = agents;
1777                         strncpy(agent, tmp, sizeof(agent) - 1);
1778                         ast_mutex_lock(&agentlock);
1779                         while (p) {
1780                                 if (!strcasecmp(p->agent, tmp)) {
1781                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1782                                         __agent_start_monitoring(chan, p, 1);
1783                                         break;
1784                                 }
1785                                 p = p->next;
1786                         }
1787                         ast_mutex_unlock(&agentlock);
1788                         
1789                 } else {
1790                         res = -1;
1791                         if (!nowarnings)
1792                                 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);
1793                 }
1794         } else {
1795                 res = -1;
1796                 if (!nowarnings)
1797                         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");
1798         }
1799         /* check if there is n + 101 priority */
1800         if (res) {
1801                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1802                         chan->priority+=100;
1803                         ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1804                }
1805                 else if (exitifnoagentid)
1806                         return res;
1807         }
1808         return 0;
1809 }
1810
1811 /*--- sip_devicestate: Part of PBX channel interface ---*/
1812 static int agent_devicestate(void *data)
1813 {
1814         struct agent_pvt *p;
1815         char *s;
1816         unsigned int groupmatch;
1817         int waitforagent=0;
1818         int res = AST_DEVICE_INVALID;
1819         
1820         s = data;
1821         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1822                 groupmatch = (1 << groupmatch);
1823         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1824                 groupmatch = (1 << groupmatch);
1825                 waitforagent = 1;
1826         } else {
1827                 groupmatch = 0;
1828         }
1829
1830         /* Check actual logged in agents first */
1831         ast_mutex_lock(&agentlock);
1832         p = agents;
1833         while(p) {
1834                 ast_mutex_lock(&p->lock);
1835                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1836                         if (p->owner) {
1837                                 if (res != AST_DEVICE_INUSE)
1838                                         res = AST_DEVICE_BUSY;
1839                         } else {
1840                                 if (res == AST_DEVICE_BUSY)
1841                                         res = AST_DEVICE_INUSE;
1842                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
1843                                         if (res == AST_DEVICE_INVALID)
1844                                                 res = AST_DEVICE_UNKNOWN;
1845                                 } else if (res == AST_DEVICE_INVALID)   
1846                                         res = AST_DEVICE_UNAVAILABLE;
1847                         }
1848                         if (!strcmp(data, p->agent)) {
1849                                 ast_mutex_unlock(&p->lock);
1850                                 break;
1851                         }
1852                 }
1853                 ast_mutex_unlock(&p->lock);
1854                 p = p->next;
1855         }
1856         ast_mutex_unlock(&agentlock);
1857         return res;
1858 }
1859
1860 int load_module()
1861 {
1862         /* Make sure we can register our sip channel type */
1863         if (ast_channel_register_ex(type, tdesc, capability, agent_request, agent_devicestate)) {
1864                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1865                 return -1;
1866         }
1867         ast_register_application(app, login_exec, synopsis, descrip);
1868         ast_register_application(app2, callback_exec, synopsis2, descrip2);
1869         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1870         ast_manager_register2("Agents", 0, action_agents, "Agents", mandescr_agents);
1871         ast_cli_register(&cli_show_agents);
1872         /* Read in the config */
1873         read_agent_config();
1874         return 0;
1875 }
1876
1877 int reload()
1878 {
1879         read_agent_config();
1880         return 0;
1881 }
1882
1883 int unload_module()
1884 {
1885         struct agent_pvt *p;
1886         /* First, take us out of the channel loop */
1887         ast_cli_unregister(&cli_show_agents);
1888         ast_unregister_application(app);
1889         ast_unregister_application(app2);
1890         ast_unregister_application(app3);
1891         ast_channel_unregister(type);
1892         ast_manager_unregister("Agents");
1893         if (!ast_mutex_lock(&agentlock)) {
1894                 /* Hangup all interfaces if they have an owner */
1895                 p = agents;
1896                 while(p) {
1897                         if (p->owner)
1898                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1899                         p = p->next;
1900                 }
1901                 agents = NULL;
1902                 ast_mutex_unlock(&agentlock);
1903         } else {
1904                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1905                 return -1;
1906         }               
1907         return 0;
1908 }
1909
1910 int usecount()
1911 {
1912         int res;
1913         ast_mutex_lock(&usecnt_lock);
1914         res = usecnt;
1915         ast_mutex_unlock(&usecnt_lock);
1916         return res;
1917 }
1918
1919 char *key()
1920 {
1921         return ASTERISK_GPL_KEY;
1922 }
1923
1924 char *description()
1925 {
1926         return desc;
1927 }
1928