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