c6b137e73f4513fe496d39a735371834480dc395
[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 /*--- action_agents: Manager routine for listing channels */
1253 static int action_agents(struct mansession *s, struct message *m)
1254 {
1255         struct agent_pvt *p;
1256         char *username = NULL;
1257         char *loginChan = NULL;
1258         char *talkingtoChan = NULL;
1259         char *status = NULL;
1260
1261         ast_mutex_lock(&agentlock);
1262         p = agents;
1263         while(p) {
1264                 ast_mutex_lock(&p->lock);
1265
1266                 /* Status Values:
1267                         AGENT_LOGGEDOFF - Agent isn't logged in
1268                         AGENT_IDLE      - Agent is logged in, and waiting for call
1269                         AGENT_ONCALL    - Agent is logged in, and on a call
1270                         AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1271
1272                 if(!ast_strlen_zero(p->name)) {
1273                         username = p->name;
1274                 } else {
1275                         username = "None";
1276                 }
1277
1278                 /* Set a default status. It 'should' get changed. */
1279                 status = "AGENT_UNKNOWN";
1280
1281                 if(p->chan) {
1282                         loginChan = p->loginchan;
1283                         if(p->owner && p->owner->_bridge) {
1284                                 talkingtoChan = p->chan->cid.cid_num;
1285                                 status = "AGENT_ONCALL";
1286                         } else {
1287                                 talkingtoChan = "n/a";
1288                                 status = "AGENT_IDLE";
1289                         }
1290                 } else if(!ast_strlen_zero(p->loginchan)) {
1291                         loginChan = p->loginchan;
1292                         talkingtoChan = "n/a";
1293                         status = "AGENT_IDLE";
1294                         if(p->acknowledged) {
1295                                 sprintf(loginChan, " %s (Confirmed)", loginChan);
1296                         }
1297                 } else {
1298                         loginChan = "n/a";
1299                         talkingtoChan = "n/a";
1300                         status = "AGENT_LOGGEDOFF";
1301                 }
1302
1303                 ast_cli(s->fd, "Event: Agents\r\n"
1304                                 "Agent: %s\r\n"
1305                                 "Name: %s\r\n"
1306                                 "Status: %s\r\n"
1307                                 "LoggedInChan: %s\r\n"
1308                                 "LoggedInTime: %ld\r\n"
1309                                 "TalkingTo: %s\r\n"
1310                                 "\r\n",
1311                                 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1312                 ast_mutex_unlock(&p->lock);
1313                 p = p->next;
1314         }
1315         ast_mutex_unlock(&agentlock);
1316         return 0;
1317 }
1318
1319 static int agent_logoff_cmd(int fd, int argc, char **argv)
1320 {
1321         struct agent_pvt *p;
1322         char *agent = argv[2] + 6;
1323         long logintime;
1324         
1325         if (argc < 3 || argc > 4)
1326                 return RESULT_SHOWUSAGE;
1327         if (argc == 4 && strcasecmp(argv[3], "soft"))
1328                 return RESULT_SHOWUSAGE;
1329
1330         for (p=agents; p; p=p->next) {
1331                 if (!strcasecmp(p->agent, agent)) {
1332                         if (argc == 3) {
1333                                 if (p->owner) {
1334                                         ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1335                                 }
1336                                 if (p->chan) {
1337                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1338                                 }
1339                         }
1340                         logintime = time(NULL) - p->loginstart;
1341                         p->loginstart = 0;
1342                         
1343                         manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1344                                 "Agent: %s\r\n"
1345                                 "Loginchan: %s\r\n"
1346                                 "Logintime: %ld\r\n",
1347                                 p->agent, p->loginchan, logintime);
1348                         ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1349                         p->loginchan[0] = '\0';
1350                         ast_cli(fd, "Logging out %s\n", agent);
1351                         break;
1352                 }
1353         }
1354         return RESULT_SUCCESS;
1355 }
1356
1357 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1358 {
1359         struct agent_pvt *p;
1360         char name[AST_MAX_AGENT];
1361         int which = 0;
1362
1363         if (pos == 2) {
1364                 for (p=agents; p; p=p->next) {
1365                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1366                         if (!strncasecmp(word, name, strlen(word))) {
1367                                 if (++which > state) {
1368                                         return strdup(name);
1369                                 }
1370                         }
1371                 }
1372         } else if (pos == 3 && state == 0) {
1373                 return strdup("soft");
1374         }
1375         return NULL;
1376 }
1377
1378 /*--- agents_show: Show agents in cli ---*/
1379 static int agents_show(int fd, int argc, char **argv)
1380 {
1381         struct agent_pvt *p;
1382         char username[AST_MAX_BUF];
1383         char location[AST_MAX_BUF] = "";
1384         char talkingto[AST_MAX_BUF] = "";
1385         char moh[AST_MAX_BUF];
1386
1387         if (argc != 2)
1388                 return RESULT_SHOWUSAGE;
1389         ast_mutex_lock(&agentlock);
1390         p = agents;
1391         while(p) {
1392                 ast_mutex_lock(&p->lock);
1393                 if (p->pending) {
1394                         if (p->group)
1395                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1396                         else
1397                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1398                 } else {
1399                         if (!ast_strlen_zero(p->name))
1400                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1401                         else
1402                                 username[0] = '\0';
1403                         if (p->chan) {
1404                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1405                                 if (p->owner && ast_bridged_channel(p->owner)) {
1406                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1407                                 } else {
1408                                         strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1409                                 }
1410                         } else if (!ast_strlen_zero(p->loginchan)) {
1411                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1412                                 talkingto[0] = '\0';
1413                                 if (p->acknowledged)
1414                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1415                         } else {
1416                                 strncpy(location, "not logged in", sizeof(location) - 1);
1417                                 talkingto[0] = '\0';
1418                         }
1419                         if (!ast_strlen_zero(p->moh))
1420                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1421                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1422                                         username, location, talkingto, moh);
1423                 }
1424                 ast_mutex_unlock(&p->lock);
1425                 p = p->next;
1426         }
1427         ast_mutex_unlock(&agentlock);
1428         return RESULT_SUCCESS;
1429 }
1430
1431 static char show_agents_usage[] = 
1432 "Usage: show agents\n"
1433 "       Provides summary information on agents.\n";
1434
1435 static char agent_logoff_usage[] =
1436 "Usage: agent logoff <channel> [soft]\n"
1437 "       Sets an agent as no longer logged in.\n"
1438 "       If 'soft' is specified, do not hangup existing calls.\n";
1439
1440 static struct ast_cli_entry cli_show_agents = {
1441         { "show", "agents", NULL }, agents_show, 
1442         "Show status of agents", show_agents_usage, NULL };
1443
1444 static struct ast_cli_entry cli_agent_logoff = {
1445         { "agent", "logoff", NULL }, agent_logoff_cmd, 
1446         "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1447
1448 STANDARD_LOCAL_USER;
1449 LOCAL_USER_DECL;
1450
1451 /*--- __login_exec: Log in agent application ---*/
1452 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1453 {
1454         int res=0;
1455         int tries = 0;
1456         int max_login_tries = maxlogintries;
1457         struct agent_pvt *p;
1458         struct localuser *u;
1459         struct timeval tv;
1460         int login_state = 0;
1461         char user[AST_MAX_AGENT] = "";
1462         char pass[AST_MAX_AGENT];
1463         char agent[AST_MAX_AGENT] = "";
1464         char xpass[AST_MAX_AGENT] = "";
1465         char *errmsg;
1466         char info[512];
1467         char *opt_user = NULL;
1468         char *options = NULL;
1469         char option;
1470         char badoption[2];
1471         char *tmpoptions = NULL;
1472         char *context = NULL;
1473         char *exten = NULL;
1474         int play_announcement = 1;
1475         char agent_goodbye[AST_MAX_FILENAME_LEN];
1476         int update_cdr = updatecdr;
1477         char *filename = "agent-loginok";
1478         
1479         strcpy(agent_goodbye, agentgoodbye);
1480         LOCAL_USER_ADD(u);
1481
1482         /* Parse the arguments XXX Check for failure XXX */
1483         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1484         opt_user = info;
1485         /* Set Channel Specific Login Overrides */
1486         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1487                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1488                 if (max_login_tries < 0)
1489                         max_login_tries = 0;
1490                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1491                 if (option_verbose > 2)
1492                         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);
1493         }
1494         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1495                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1496                         update_cdr = 1;
1497                 else
1498                         update_cdr = 0;
1499                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1500                 if (option_verbose > 2)
1501                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1502         }
1503         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1504                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1505                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1506                 if (option_verbose > 2)
1507                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1508         }
1509         /* End Channel Specific Login Overrides */
1510         /* Read command line options */
1511          if( opt_user ) {
1512                 options = strchr(opt_user, '|');
1513                 if (options) {
1514                         *options = '\0';
1515                         options++;
1516                         if (callbackmode) {
1517                                 context = strchr(options, '@');
1518                                 if (context) {
1519                                         *context = '\0';
1520                                         context++;
1521                                 }
1522                                 exten = options;
1523                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1524                                 if (!*exten)
1525                                         exten = NULL;
1526                         }
1527                 }
1528                 if (options) {
1529                         while (*options) {
1530                                 option = (char)options[0];
1531                                 if ((option >= 0) && (option <= '9'))
1532                                 {
1533                                         options++;
1534                                         continue;
1535                                 }
1536                                 if (option=='s')
1537                                         play_announcement = 0;
1538                                 else {
1539                                         badoption[0] = option;
1540                                         badoption[1] = '\0';
1541                                         tmpoptions=badoption;
1542                                         if (option_verbose > 2)
1543                                                 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1544                                 }
1545                                 options++;
1546                         }
1547                 }
1548         }
1549         /* End command line options */
1550
1551         if (chan->_state != AST_STATE_UP)
1552                 res = ast_answer(chan);
1553         if (!res) {
1554                 if( opt_user && !ast_strlen_zero(opt_user))
1555                         strncpy( user, opt_user, AST_MAX_AGENT - 1);
1556                 else
1557                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1558         }
1559         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1560                 tries++;
1561                 /* Check for password */
1562                 ast_mutex_lock(&agentlock);
1563                 p = agents;
1564                 while(p) {
1565                         if (!strcmp(p->agent, user) && !p->pending)
1566                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1567                         p = p->next;
1568                 }
1569                 ast_mutex_unlock(&agentlock);
1570                 if (!res) {
1571                         if (!ast_strlen_zero(xpass))
1572                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1573                         else
1574                                 pass[0] = '\0';
1575                 }
1576                 errmsg = "agent-incorrect";
1577
1578 #if 0
1579                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1580 #endif          
1581
1582                 /* Check again for accuracy */
1583                 ast_mutex_lock(&agentlock);
1584                 p = agents;
1585                 while(p) {
1586                         ast_mutex_lock(&p->lock);
1587                         if (!strcmp(p->agent, user) &&
1588                                 !strcmp(p->password, pass) && !p->pending) {
1589                                         login_state = 1; /* Successful Login */
1590                                         /* Set Channel Specific Agent Overides */
1591                                         if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1592                                                 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1593                                                         p->ackcall = 2;
1594                                                 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1595                                                         p->ackcall = 1;
1596                                                 else
1597                                                         p->ackcall = 0;
1598                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1599                                                 if (option_verbose > 2)
1600                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1601                                         }
1602                                         if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1603                                                 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1604                                                 if (p->autologoff < 0)
1605                                                         p->autologoff = 0;
1606                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1607                                                 if (option_verbose > 2)
1608                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1609                                         }
1610                                         if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1611                                                 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1612                                                 if (p->wrapuptime < 0)
1613                                                         p->wrapuptime = 0;
1614                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1615                                                 if (option_verbose > 2)
1616                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1617                                         }
1618                                         /* End Channel Specific Agent Overides */
1619                                         if (!p->chan) {
1620                                                 char last_loginchan[80] = "";
1621                                                 long logintime;
1622                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1623
1624                                                 if (callbackmode) {
1625                                                         char tmpchan[AST_MAX_BUF] = "";
1626                                                         int pos = 0;
1627                                                         /* Retrieve login chan */
1628                                                         for (;;) {
1629                                                                 if (exten) {
1630                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1631                                                                         res = 0;
1632                                                                 } else
1633                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1634                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1635                                                                                         1, NULL))
1636                                                                         break;
1637                                                                 if (exten) {
1638                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1639                                                                         exten = NULL;
1640                                                                         pos = 0;
1641                                                                 } else {
1642                                                                         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);
1643                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1644                                                                         if (!res)
1645                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1646                                                                         if (res > 0) {
1647                                                                                 tmpchan[0] = res;
1648                                                                                 tmpchan[1] = '\0';
1649                                                                                 pos = 1;
1650                                                                         } else {
1651                                                                                 tmpchan[0] = '\0';
1652                                                                                 pos = 0;
1653                                                                         }
1654                                                                 }
1655                                                         }
1656                                                         exten = tmpchan;
1657                                                         if (!res) {
1658                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1659                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1660                                                                 else {
1661                                                                         strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1662                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1663                                                                 }
1664                                                                 if (ast_strlen_zero(p->loginchan)) {
1665                                                                         login_state = 2;
1666                                                                         filename = "agent-loggedoff";
1667                                                                 }
1668                                                                 p->acknowledged = 0;
1669                                                                 /* store/clear the global variable that stores agentid based on the callerid */
1670                                                                 if (chan->cid.cid_num) {
1671                                                                         char agentvar[AST_MAX_BUF];
1672                                                                         snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1673                                                                         if (ast_strlen_zero(p->loginchan))
1674                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1675                                                                         else
1676                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1677                                                                 }
1678                                                                 if(update_cdr && chan->cdr)
1679                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1680
1681                                                         }
1682                                                 } else {
1683                                                         p->loginchan[0] = '\0';
1684                                                         p->acknowledged = 0;
1685                                                 }
1686                                                 ast_mutex_unlock(&p->lock);
1687                                                 ast_mutex_unlock(&agentlock);
1688                                                 if( !res && play_announcement==1 )
1689                                                         res = ast_streamfile(chan, filename, chan->language);
1690                                                 if (!res)
1691                                                         ast_waitstream(chan, "");
1692                                                 ast_mutex_lock(&agentlock);
1693                                                 ast_mutex_lock(&p->lock);
1694                                                 if (!res) {
1695                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1696                                                         if (res)
1697                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1698                                                 }
1699                                                 if (!res) {
1700                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1701                                                         if (res)
1702                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1703                                                 }
1704                                                 /* Check once more just in case */
1705                                                 if (p->chan)
1706                                                         res = -1;
1707                                                 if (callbackmode && !res) {
1708                                                         /* Just say goodbye and be done with it */
1709                                                         if (!ast_strlen_zero(p->loginchan)) {
1710                                                                 if (p->loginstart == 0)
1711                                                                         time(&p->loginstart);
1712                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1713                                                                         "Agent: %s\r\n"
1714                                                                         "Loginchan: %s\r\n"
1715                                                                         "Uniqueid: %s\r\n",
1716                                                                         p->agent, p->loginchan, chan->uniqueid);
1717                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1718                                                                 if (option_verbose > 1)
1719                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1720                                                                 ast_device_state_changed("Agent/%s", p->agent);
1721                                                         } else {
1722                                                                 logintime = time(NULL) - p->loginstart;
1723                                                                 p->loginstart = 0;
1724                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1725                                                                         "Agent: %s\r\n"
1726                                                                         "Loginchan: %s\r\n"
1727                                                                         "Logintime: %ld\r\n"
1728                                                                         "Uniqueid: %s\r\n",
1729                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1730                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1731                                                                 if (option_verbose > 1)
1732                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1733                                                                 ast_device_state_changed("Agent/%s", p->agent);
1734                                                         }
1735                                                         ast_mutex_unlock(&agentlock);
1736                                                         if (!res)
1737                                                                 res = ast_safe_sleep(chan, 500);
1738                                                         ast_mutex_unlock(&p->lock);
1739                                                         if (persistent_agents)
1740                                                                 dump_agents();
1741                                                 } else if (!res) {
1742 #ifdef HONOR_MUSIC_CLASS
1743                                                         /* check if the moh class was changed with setmusiconhold */
1744                                                         if (*(chan->musicclass))
1745                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1746 #endif                                                          
1747                                                         ast_moh_start(chan, p->moh);
1748                                                         if (p->loginstart == 0)
1749                                                                 time(&p->loginstart);
1750                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1751                                                                 "Agent: %s\r\n"
1752                                                                 "Channel: %s\r\n"
1753                                                                 "Uniqueid: %s\r\n",
1754                                                                 p->agent, chan->name, chan->uniqueid);
1755                                                         if (update_cdr && chan->cdr)
1756                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1757                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1758                                                         if (option_verbose > 1)
1759                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1760                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1761                                                         /* Login this channel and wait for it to
1762                                                            go away */
1763                                                         p->chan = chan;
1764                                                         if (p->ackcall > 1)
1765                                                                 check_beep(p, 0);
1766                                                         else
1767                                                                 check_availability(p, 0);
1768                                                         ast_mutex_unlock(&p->lock);
1769                                                         ast_mutex_unlock(&agentlock);
1770                                                         ast_device_state_changed("Agent/%s", p->agent);
1771                                                         while (res >= 0) {
1772                                                                 ast_mutex_lock(&p->lock);
1773                                                                 if (p->chan != chan)
1774                                                                         res = -1;
1775                                                                 ast_mutex_unlock(&p->lock);
1776                                                                 /* Yield here so other interested threads can kick in. */
1777                                                                 sched_yield();
1778                                                                 if (res)
1779                                                                         break;
1780
1781                                                                 ast_mutex_lock(&agentlock);
1782                                                                 ast_mutex_lock(&p->lock);
1783                                                                 if (p->lastdisc.tv_sec) {
1784                                                                         gettimeofday(&tv, NULL);
1785                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1786                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1787                                                                                         if (option_debug)
1788                                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1789                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1790                                                                                 if (p->ackcall > 1)
1791                                                                                         check_beep(p, 0);
1792                                                                                 else
1793                                                                                         check_availability(p, 0);
1794                                                                         }
1795                                                                 }
1796                                                                 ast_mutex_unlock(&p->lock);
1797                                                                 ast_mutex_unlock(&agentlock);
1798                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1799                                                                 ast_mutex_lock( &p->app_lock );
1800                                                                 ast_mutex_lock(&p->lock);
1801                                                                 p->owning_app = pthread_self();
1802                                                                 ast_mutex_unlock(&p->lock);
1803                                                                 if (p->ackcall > 1) 
1804                                                                         res = agent_ack_sleep(p);
1805                                                                 else
1806                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1807                                                                                                         agent_cont_sleep, p );
1808                                                                 ast_mutex_unlock( &p->app_lock );
1809                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1810                                                                         ast_mutex_lock(&agentlock);
1811                                                                         ast_mutex_lock(&p->lock);
1812                                                                         check_availability(p, 0);
1813                                                                         ast_mutex_unlock(&p->lock);
1814                                                                         ast_mutex_unlock(&agentlock);
1815                                                                         res = 0;
1816                                                                 }
1817                                                                 sched_yield();
1818                                                         }
1819                                                         ast_mutex_lock(&p->lock);
1820                                                         if (res && p->owner) 
1821                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1822                                                         /* Log us off if appropriate */
1823                                                         if (p->chan == chan)
1824                                                                 p->chan = NULL;
1825                                                         p->acknowledged = 0;
1826                                                         logintime = time(NULL) - p->loginstart;
1827                                                         p->loginstart = 0;
1828                                                         ast_mutex_unlock(&p->lock);
1829                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1830                                                                 "Agent: %s\r\n"
1831                                                                 "Logintime: %ld\r\n"
1832                                                                 "Uniqueid: %s\r\n",
1833                                                                 p->agent, logintime, chan->uniqueid);
1834                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1835                                                         if (option_verbose > 1)
1836                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1837                                                         /* If there is no owner, go ahead and kill it now */
1838                                                         ast_device_state_changed("Agent/%s", p->agent);
1839                                                         if (p->dead && !p->owner) {
1840                                                                 ast_mutex_destroy(&p->lock);
1841                                                                 ast_mutex_destroy(&p->app_lock);
1842                                                                 free(p);
1843                                                         }
1844                                                 }
1845                                                 else {
1846                                                         ast_mutex_unlock(&p->lock);
1847                                                         p = NULL;
1848                                                 }
1849                                                 res = -1;
1850                                         } else {
1851                                                 ast_mutex_unlock(&p->lock);
1852                                                 errmsg = "agent-alreadyon";
1853                                                 p = NULL;
1854                                         }
1855                                         break;
1856                         }
1857                         ast_mutex_unlock(&p->lock);
1858                         p = p->next;
1859                 }
1860                 if (!p)
1861                         ast_mutex_unlock(&agentlock);
1862
1863                 if (!res && (max_login_tries==0 || tries < max_login_tries))
1864                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1865         }
1866                 
1867         LOCAL_USER_REMOVE(u);
1868         if (!res)
1869                 res = ast_safe_sleep(chan, 500);
1870
1871         /* AgentLogin() exit */
1872         if (!callbackmode) {
1873                 return -1;
1874         }
1875         /* AgentCallbackLogin() exit*/
1876         else {
1877                 /* Set variables */
1878                 if (login_state > 0) {
1879                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1880                         if (login_state==1) {
1881                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1882                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1883                         }
1884                         else {
1885                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1886                         }
1887                 }
1888                 else {
1889                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1890                 }
1891                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1892                         return 0;
1893                 /* Do we need to play agent-goodbye now that we will be hanging up? */
1894                 if (play_announcement==1) {
1895                         if (!res)
1896                                 res = ast_safe_sleep(chan, 1000);
1897                         res = ast_streamfile(chan, agent_goodbye, chan->language);
1898                         if (!res)
1899                                 res = ast_waitstream(chan, "");
1900                         if (!res)
1901                                 res = ast_safe_sleep(chan, 1000);
1902                 }
1903         }
1904         /* We should never get here if next priority exists when in callbackmode */
1905         return -1;
1906 }
1907
1908 static int login_exec(struct ast_channel *chan, void *data)
1909 {
1910         return __login_exec(chan, data, 0);
1911 }
1912
1913 static int callback_exec(struct ast_channel *chan, void *data)
1914 {
1915         return __login_exec(chan, data, 1);
1916 }
1917
1918 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1919 {
1920         int exitifnoagentid = 0;
1921         int nowarnings = 0;
1922         int changeoutgoing = 0;
1923         int res = 0;
1924         char agent[AST_MAX_AGENT], *tmp;
1925
1926         if (data) {
1927                 if (strchr(data, 'd'))
1928                         exitifnoagentid = 1;
1929                 if (strchr(data, 'n'))
1930                         nowarnings = 1;
1931                 if (strchr(data, 'c'))
1932                         changeoutgoing = 1;
1933         }
1934         if (chan->cid.cid_num) {
1935                 char agentvar[AST_MAX_BUF];
1936                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1937                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1938                         struct agent_pvt *p = agents;
1939                         strncpy(agent, tmp, sizeof(agent) - 1);
1940                         ast_mutex_lock(&agentlock);
1941                         while (p) {
1942                                 if (!strcasecmp(p->agent, tmp)) {
1943                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1944                                         __agent_start_monitoring(chan, p, 1);
1945                                         break;
1946                                 }
1947                                 p = p->next;
1948                         }
1949                         ast_mutex_unlock(&agentlock);
1950                         
1951                 } else {
1952                         res = -1;
1953                         if (!nowarnings)
1954                                 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);
1955                 }
1956         } else {
1957                 res = -1;
1958                 if (!nowarnings)
1959                         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");
1960         }
1961         /* check if there is n + 101 priority */
1962         if (res) {
1963                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1964                         chan->priority+=100;
1965                         if (option_verbose > 2)
1966                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1967                }
1968                 else if (exitifnoagentid)
1969                         return res;
1970         }
1971         return 0;
1972 }
1973
1974 /* Dump AgentCallbackLogin agents to the database for persistence
1975  */
1976
1977 static void dump_agents(void)
1978 {
1979         struct agent_pvt *cur_agent = NULL;
1980
1981         for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
1982                 if (cur_agent->chan)
1983                         continue;
1984
1985                 if (!ast_strlen_zero(cur_agent->loginchan)) {
1986                         if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan))
1987                                 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
1988                         else if (option_debug)
1989                                 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
1990                 } else {
1991                         /* Delete -  no agent or there is an error */
1992                         ast_db_del(pa_family, cur_agent->agent);
1993                 }
1994         }
1995 }
1996
1997 /* Reload the persistent agents from astdb */
1998 static void reload_agents(void)
1999 {
2000         char *agent_num;
2001         struct ast_db_entry *db_tree;
2002         struct ast_db_entry *entry;
2003         struct agent_pvt *cur_agent;
2004         char agent_data[80];
2005
2006         db_tree = ast_db_gettree(pa_family, NULL);
2007
2008         ast_mutex_lock(&agentlock);
2009         for (entry = db_tree; entry; entry = entry->next) {
2010                 agent_num = db_tree->key + strlen(pa_family) + 2;
2011                 cur_agent = agents;
2012                 while (cur_agent) {
2013                         ast_mutex_lock(&cur_agent->lock);
2014                         if (strcmp(agent_num, cur_agent->agent) == 0)
2015                                 break;
2016                         ast_mutex_unlock(&cur_agent->lock);
2017                         cur_agent = cur_agent->next;
2018                 }
2019                 if (!cur_agent) {
2020                         ast_db_del(pa_family, agent_num);
2021                         continue;
2022                 } else
2023                         ast_mutex_unlock(&cur_agent->lock);
2024                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2025                         if (option_debug)
2026                                 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2027                         strncpy(cur_agent->loginchan, agent_data, sizeof(cur_agent->loginchan)-1);
2028                         if (cur_agent->loginstart == 0)
2029                                 time(&cur_agent->loginstart);
2030                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2031                 }
2032         }
2033         ast_mutex_unlock(&agentlock);
2034         if (db_tree) {
2035                 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2036                 ast_db_freetree(db_tree);
2037         }
2038 }
2039
2040
2041 /*--- agent_devicestate: Part of PBX channel interface ---*/
2042 static int agent_devicestate(void *data)
2043 {
2044         struct agent_pvt *p;
2045         char *s;
2046         ast_group_t groupmatch;
2047         int groupoff;
2048         int waitforagent=0;
2049         int res = AST_DEVICE_INVALID;
2050         
2051         s = data;
2052         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2053                 groupmatch = (1 << groupoff);
2054         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2055                 groupmatch = (1 << groupoff);
2056                 waitforagent = 1;
2057         } else {
2058                 groupmatch = 0;
2059         }
2060
2061         /* Check actual logged in agents first */
2062         ast_mutex_lock(&agentlock);
2063         p = agents;
2064         while(p) {
2065                 ast_mutex_lock(&p->lock);
2066                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2067                         if (p->owner) {
2068                                 if (res != AST_DEVICE_INUSE)
2069                                         res = AST_DEVICE_BUSY;
2070                         } else {
2071                                 if (res == AST_DEVICE_BUSY)
2072                                         res = AST_DEVICE_INUSE;
2073                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2074                                         if (res == AST_DEVICE_INVALID)
2075                                                 res = AST_DEVICE_UNKNOWN;
2076                                 } else if (res == AST_DEVICE_INVALID)   
2077                                         res = AST_DEVICE_UNAVAILABLE;
2078                         }
2079                         if (!strcmp(data, p->agent)) {
2080                                 ast_mutex_unlock(&p->lock);
2081                                 break;
2082                         }
2083                 }
2084                 ast_mutex_unlock(&p->lock);
2085                 p = p->next;
2086         }
2087         ast_mutex_unlock(&agentlock);
2088         return res;
2089 }
2090
2091 /*--- load_module: Initialize channel module ---*/
2092 int load_module()
2093 {
2094         /* Make sure we can register our agent channel type */
2095         if (ast_channel_register_ex(channeltype, tdesc, capability, agent_request, agent_devicestate)) {
2096                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2097                 return -1;
2098         }
2099         /* Dialplan applications */
2100         ast_register_application(app, login_exec, synopsis, descrip);
2101         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2102         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2103         /* Manager command */
2104         ast_manager_register2("Agents", 0, action_agents, "Lists agents and their status", mandescr_agents);
2105         /* CLI Application */
2106         ast_cli_register(&cli_show_agents);
2107         ast_cli_register(&cli_agent_logoff);
2108         /* Read in the config */
2109         read_agent_config();
2110         if (persistent_agents)
2111                 reload_agents();
2112         return 0;
2113 }
2114
2115 int reload()
2116 {
2117         read_agent_config();
2118         if (persistent_agents)
2119                 reload_agents();
2120         return 0;
2121 }
2122
2123 int unload_module()
2124 {
2125         struct agent_pvt *p;
2126         /* First, take us out of the channel loop */
2127         /* Unregister CLI application */
2128         ast_cli_unregister(&cli_show_agents);
2129         ast_cli_unregister(&cli_agent_logoff);
2130         /* Unregister dialplan applications */
2131         ast_unregister_application(app);
2132         ast_unregister_application(app2);
2133         ast_unregister_application(app3);
2134         /* Unregister manager command */
2135         ast_manager_unregister("Agents");
2136         /* Unregister channel */
2137         ast_channel_unregister(channeltype);
2138         if (!ast_mutex_lock(&agentlock)) {
2139                 /* Hangup all interfaces if they have an owner */
2140                 p = agents;
2141                 while(p) {
2142                         if (p->owner)
2143                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2144                         p = p->next;
2145                 }
2146                 agents = NULL;
2147                 ast_mutex_unlock(&agentlock);
2148         } else {
2149                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2150                 return -1;
2151         }               
2152         return 0;
2153 }
2154
2155 int usecount()
2156 {
2157         int res;
2158         ast_mutex_lock(&usecnt_lock);
2159         res = usecnt;
2160         ast_mutex_unlock(&usecnt_lock);
2161         return res;
2162 }
2163
2164 char *key()
2165 {
2166         return ASTERISK_GPL_KEY;
2167 }
2168
2169 char *description()
2170 {
2171         return desc;
2172 }
2173