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