Adding support to log off an agent from the console
[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 int agent_logoff(int fd, int argc, char **argv)
1426 {
1427         struct agent_pvt *p = NULL;
1428         char *line = NULL;
1429         int res = 0;
1430
1431         /* Check args */
1432         if (argc != 3)
1433                 return RESULT_SHOWUSAGE;
1434         
1435         line = argv[2];
1436
1437         ast_mutex_lock(&agentlock);
1438         p = agents;
1439         while (p) {
1440                 ast_mutex_lock(&p->lock);
1441                 res = strcmp(p->agent, line);
1442
1443                 if (!res) {
1444                         /* Found him! Now we're going to kill him. */
1445                         
1446                         if (ast_strlen_zero(p->loginchan)) {
1447                                 ast_cli(fd, "Agent %s already logged off the system.\n", line);
1448                                 ast_mutex_unlock(&p->lock);
1449                                 break;
1450                         }
1451                                 
1452                         strcpy(p->loginchan, ""); /* Bang! Killed him */
1453                         ast_cli(fd, "Agent %s successfully logged off.\n", line);
1454                         ast_mutex_unlock(&p->lock);
1455                         break;
1456                 }
1457                 
1458                 ast_mutex_unlock(&p->lock);
1459                 p = p->next;
1460         }
1461         ast_mutex_unlock(&agentlock);
1462         if (res) ast_cli(fd, "Unable to find agent %s.\n", line);
1463         return RESULT_SUCCESS;
1464 }
1465
1466 static char agent_logoff_usage[] =
1467 "Usage: agent logoff <agentnum>\n"
1468 "       Log an agent off the system that maybe forgot to log off, etc....\n";
1469
1470 static struct ast_cli_entry cli_agent_logoff = {
1471         { "agent", "logoff", NULL }, agent_logoff,
1472         "Log an agent off of the system", agent_logoff_usage, NULL};
1473
1474 static char show_agents_usage[] = 
1475 "Usage: show agents\n"
1476 "       Provides summary information on agents.\n";
1477
1478 static char agent_logoff_usage[] =
1479 "Usage: agent logoff <channel> [soft]\n"
1480 "       Sets an agent as no longer logged in.\n"
1481 "       If 'soft' is specified, do not hangup existing calls.\n";
1482
1483 static struct ast_cli_entry cli_show_agents = {
1484         { "show", "agents", NULL }, agents_show, 
1485         "Show status of agents", show_agents_usage, NULL };
1486
1487 static struct ast_cli_entry cli_agent_logoff = {
1488         { "agent", "logoff", NULL }, agent_logoff_cmd, 
1489         "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1490
1491 STANDARD_LOCAL_USER;
1492 LOCAL_USER_DECL;
1493
1494 /*--- __login_exec: Log in agent application ---*/
1495 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1496 {
1497         int res=0;
1498         int tries = 0;
1499         int max_login_tries = maxlogintries;
1500         struct agent_pvt *p;
1501         struct localuser *u;
1502         struct timeval tv;
1503         int login_state = 0;
1504         char user[AST_MAX_AGENT] = "";
1505         char pass[AST_MAX_AGENT];
1506         char agent[AST_MAX_AGENT] = "";
1507         char xpass[AST_MAX_AGENT] = "";
1508         char *errmsg;
1509         char info[512];
1510         char *opt_user = NULL;
1511         char *options = NULL;
1512         char option;
1513         char badoption[2];
1514         char *tmpoptions = NULL;
1515         char *context = NULL;
1516         char *exten = NULL;
1517         int play_announcement = 1;
1518         char agent_goodbye[AST_MAX_FILENAME_LEN];
1519         int update_cdr = updatecdr;
1520         char *filename = "agent-loginok";
1521         
1522         strcpy(agent_goodbye, agentgoodbye);
1523         LOCAL_USER_ADD(u);
1524
1525         /* Parse the arguments XXX Check for failure XXX */
1526         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1527         opt_user = info;
1528         /* Set Channel Specific Login Overrides */
1529         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1530                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1531                 if (max_login_tries < 0)
1532                         max_login_tries = 0;
1533                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1534                 if (option_verbose > 2)
1535                         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);
1536         }
1537         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1538                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1539                         update_cdr = 1;
1540                 else
1541                         update_cdr = 0;
1542                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1543                 if (option_verbose > 2)
1544                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1545         }
1546         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1547                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1548                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1549                 if (option_verbose > 2)
1550                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1551         }
1552         /* End Channel Specific Login Overrides */
1553         /* Read command line options */
1554          if( opt_user ) {
1555                 options = strchr(opt_user, '|');
1556                 if (options) {
1557                         *options = '\0';
1558                         options++;
1559                         if (callbackmode) {
1560                                 context = strchr(options, '@');
1561                                 if (context) {
1562                                         *context = '\0';
1563                                         context++;
1564                                 }
1565                                 exten = options;
1566                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1567                                 if (!*exten)
1568                                         exten = NULL;
1569                         }
1570                 }
1571                 if (options) {
1572                         while (*options) {
1573                                 option = (char)options[0];
1574                                 if ((option >= 0) && (option <= '9'))
1575                                 {
1576                                         options++;
1577                                         continue;
1578                                 }
1579                                 if (option=='s')
1580                                         play_announcement = 0;
1581                                 else {
1582                                         badoption[0] = option;
1583                                         badoption[1] = '\0';
1584                                         tmpoptions=badoption;
1585                                         if (option_verbose > 2)
1586                                                 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1587                                 }
1588                                 options++;
1589                         }
1590                 }
1591         }
1592         /* End command line options */
1593
1594         if (chan->_state != AST_STATE_UP)
1595                 res = ast_answer(chan);
1596         if (!res) {
1597                 if( opt_user && !ast_strlen_zero(opt_user))
1598                         strncpy( user, opt_user, AST_MAX_AGENT - 1);
1599                 else
1600                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1601         }
1602         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1603                 tries++;
1604                 /* Check for password */
1605                 ast_mutex_lock(&agentlock);
1606                 p = agents;
1607                 while(p) {
1608                         if (!strcmp(p->agent, user) && !p->pending)
1609                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1610                         p = p->next;
1611                 }
1612                 ast_mutex_unlock(&agentlock);
1613                 if (!res) {
1614                         if (!ast_strlen_zero(xpass))
1615                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1616                         else
1617                                 pass[0] = '\0';
1618                 }
1619                 errmsg = "agent-incorrect";
1620
1621 #if 0
1622                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1623 #endif          
1624
1625                 /* Check again for accuracy */
1626                 ast_mutex_lock(&agentlock);
1627                 p = agents;
1628                 while(p) {
1629                         ast_mutex_lock(&p->lock);
1630                         if (!strcmp(p->agent, user) &&
1631                                 !strcmp(p->password, pass) && !p->pending) {
1632                                         login_state = 1; /* Successful Login */
1633                                         /* Set Channel Specific Agent Overides */
1634                                         if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1635                                                 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1636                                                         p->ackcall = 2;
1637                                                 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1638                                                         p->ackcall = 1;
1639                                                 else
1640                                                         p->ackcall = 0;
1641                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1642                                                 if (option_verbose > 2)
1643                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1644                                         }
1645                                         if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1646                                                 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1647                                                 if (p->autologoff < 0)
1648                                                         p->autologoff = 0;
1649                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1650                                                 if (option_verbose > 2)
1651                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1652                                         }
1653                                         if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1654                                                 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1655                                                 if (p->wrapuptime < 0)
1656                                                         p->wrapuptime = 0;
1657                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1658                                                 if (option_verbose > 2)
1659                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1660                                         }
1661                                         /* End Channel Specific Agent Overides */
1662                                         if (!p->chan) {
1663                                                 char last_loginchan[80] = "";
1664                                                 long logintime;
1665                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1666
1667                                                 if (callbackmode) {
1668                                                         char tmpchan[AST_MAX_BUF] = "";
1669                                                         int pos = 0;
1670                                                         /* Retrieve login chan */
1671                                                         for (;;) {
1672                                                                 if (exten) {
1673                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1674                                                                         res = 0;
1675                                                                 } else
1676                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1677                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1678                                                                                         1, NULL))
1679                                                                         break;
1680                                                                 if (exten) {
1681                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1682                                                                         exten = NULL;
1683                                                                         pos = 0;
1684                                                                 } else {
1685                                                                         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);
1686                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1687                                                                         if (!res)
1688                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1689                                                                         if (res > 0) {
1690                                                                                 tmpchan[0] = res;
1691                                                                                 tmpchan[1] = '\0';
1692                                                                                 pos = 1;
1693                                                                         } else {
1694                                                                                 tmpchan[0] = '\0';
1695                                                                                 pos = 0;
1696                                                                         }
1697                                                                 }
1698                                                         }
1699                                                         exten = tmpchan;
1700                                                         if (!res) {
1701                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1702                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1703                                                                 else {
1704                                                                         strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1705                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1706                                                                 }
1707                                                                 if (ast_strlen_zero(p->loginchan)) {
1708                                                                         login_state = 2;
1709                                                                         filename = "agent-loggedoff";
1710                                                                 }
1711                                                                 p->acknowledged = 0;
1712                                                                 /* store/clear the global variable that stores agentid based on the callerid */
1713                                                                 if (chan->cid.cid_num) {
1714                                                                         char agentvar[AST_MAX_BUF];
1715                                                                         snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1716                                                                         if (ast_strlen_zero(p->loginchan))
1717                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1718                                                                         else
1719                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1720                                                                 }
1721                                                                 if(update_cdr && chan->cdr)
1722                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1723
1724                                                         }
1725                                                 } else {
1726                                                         p->loginchan[0] = '\0';
1727                                                         p->acknowledged = 0;
1728                                                 }
1729                                                 ast_mutex_unlock(&p->lock);
1730                                                 ast_mutex_unlock(&agentlock);
1731                                                 if( !res && play_announcement==1 )
1732                                                         res = ast_streamfile(chan, filename, chan->language);
1733                                                 if (!res)
1734                                                         ast_waitstream(chan, "");
1735                                                 ast_mutex_lock(&agentlock);
1736                                                 ast_mutex_lock(&p->lock);
1737                                                 if (!res) {
1738                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1739                                                         if (res)
1740                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1741                                                 }
1742                                                 if (!res) {
1743                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1744                                                         if (res)
1745                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1746                                                 }
1747                                                 /* Check once more just in case */
1748                                                 if (p->chan)
1749                                                         res = -1;
1750                                                 if (callbackmode && !res) {
1751                                                         /* Just say goodbye and be done with it */
1752                                                         if (!ast_strlen_zero(p->loginchan)) {
1753                                                                 if (p->loginstart == 0)
1754                                                                         time(&p->loginstart);
1755                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1756                                                                         "Agent: %s\r\n"
1757                                                                         "Loginchan: %s\r\n"
1758                                                                         "Uniqueid: %s\r\n",
1759                                                                         p->agent, p->loginchan, chan->uniqueid);
1760                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1761                                                                 if (option_verbose > 1)
1762                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1763                                                                 ast_device_state_changed("Agent/%s", p->agent);
1764                                                         } else {
1765                                                                 logintime = time(NULL) - p->loginstart;
1766                                                                 p->loginstart = 0;
1767                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1768                                                                         "Agent: %s\r\n"
1769                                                                         "Loginchan: %s\r\n"
1770                                                                         "Logintime: %ld\r\n"
1771                                                                         "Uniqueid: %s\r\n",
1772                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1773                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1774                                                                 if (option_verbose > 1)
1775                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1776                                                                 ast_device_state_changed("Agent/%s", p->agent);
1777                                                         }
1778                                                         ast_mutex_unlock(&agentlock);
1779                                                         if (!res)
1780                                                                 res = ast_safe_sleep(chan, 500);
1781                                                         ast_mutex_unlock(&p->lock);
1782                                                         if (persistent_agents)
1783                                                                 dump_agents();
1784                                                 } else if (!res) {
1785 #ifdef HONOR_MUSIC_CLASS
1786                                                         /* check if the moh class was changed with setmusiconhold */
1787                                                         if (*(chan->musicclass))
1788                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1789 #endif                                                          
1790                                                         ast_moh_start(chan, p->moh);
1791                                                         if (p->loginstart == 0)
1792                                                                 time(&p->loginstart);
1793                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1794                                                                 "Agent: %s\r\n"
1795                                                                 "Channel: %s\r\n"
1796                                                                 "Uniqueid: %s\r\n",
1797                                                                 p->agent, chan->name, chan->uniqueid);
1798                                                         if (update_cdr && chan->cdr)
1799                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1800                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1801                                                         if (option_verbose > 1)
1802                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1803                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1804                                                         /* Login this channel and wait for it to
1805                                                            go away */
1806                                                         p->chan = chan;
1807                                                         if (p->ackcall > 1)
1808                                                                 check_beep(p, 0);
1809                                                         else
1810                                                                 check_availability(p, 0);
1811                                                         ast_mutex_unlock(&p->lock);
1812                                                         ast_mutex_unlock(&agentlock);
1813                                                         ast_device_state_changed("Agent/%s", p->agent);
1814                                                         while (res >= 0) {
1815                                                                 ast_mutex_lock(&p->lock);
1816                                                                 if (p->chan != chan)
1817                                                                         res = -1;
1818                                                                 ast_mutex_unlock(&p->lock);
1819                                                                 /* Yield here so other interested threads can kick in. */
1820                                                                 sched_yield();
1821                                                                 if (res)
1822                                                                         break;
1823
1824                                                                 ast_mutex_lock(&agentlock);
1825                                                                 ast_mutex_lock(&p->lock);
1826                                                                 if (p->lastdisc.tv_sec) {
1827                                                                         gettimeofday(&tv, NULL);
1828                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1829                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1830                                                                                         if (option_debug)
1831                                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1832                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1833                                                                                 if (p->ackcall > 1)
1834                                                                                         check_beep(p, 0);
1835                                                                                 else
1836                                                                                         check_availability(p, 0);
1837                                                                         }
1838                                                                 }
1839                                                                 ast_mutex_unlock(&p->lock);
1840                                                                 ast_mutex_unlock(&agentlock);
1841                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1842                                                                 ast_mutex_lock( &p->app_lock );
1843                                                                 ast_mutex_lock(&p->lock);
1844                                                                 p->owning_app = pthread_self();
1845                                                                 ast_mutex_unlock(&p->lock);
1846                                                                 if (p->ackcall > 1) 
1847                                                                         res = agent_ack_sleep(p);
1848                                                                 else
1849                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1850                                                                                                         agent_cont_sleep, p );
1851                                                                 ast_mutex_unlock( &p->app_lock );
1852                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1853                                                                         ast_mutex_lock(&agentlock);
1854                                                                         ast_mutex_lock(&p->lock);
1855                                                                         check_availability(p, 0);
1856                                                                         ast_mutex_unlock(&p->lock);
1857                                                                         ast_mutex_unlock(&agentlock);
1858                                                                         res = 0;
1859                                                                 }
1860                                                                 sched_yield();
1861                                                         }
1862                                                         ast_mutex_lock(&p->lock);
1863                                                         if (res && p->owner) 
1864                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1865                                                         /* Log us off if appropriate */
1866                                                         if (p->chan == chan)
1867                                                                 p->chan = NULL;
1868                                                         p->acknowledged = 0;
1869                                                         logintime = time(NULL) - p->loginstart;
1870                                                         p->loginstart = 0;
1871                                                         ast_mutex_unlock(&p->lock);
1872                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1873                                                                 "Agent: %s\r\n"
1874                                                                 "Logintime: %ld\r\n"
1875                                                                 "Uniqueid: %s\r\n",
1876                                                                 p->agent, logintime, chan->uniqueid);
1877                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1878                                                         if (option_verbose > 1)
1879                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1880                                                         /* If there is no owner, go ahead and kill it now */
1881                                                         ast_device_state_changed("Agent/%s", p->agent);
1882                                                         if (p->dead && !p->owner) {
1883                                                                 ast_mutex_destroy(&p->lock);
1884                                                                 ast_mutex_destroy(&p->app_lock);
1885                                                                 free(p);
1886                                                         }
1887                                                 }
1888                                                 else {
1889                                                         ast_mutex_unlock(&p->lock);
1890                                                         p = NULL;
1891                                                 }
1892                                                 res = -1;
1893                                         } else {
1894                                                 ast_mutex_unlock(&p->lock);
1895                                                 errmsg = "agent-alreadyon";
1896                                                 p = NULL;
1897                                         }
1898                                         break;
1899                         }
1900                         ast_mutex_unlock(&p->lock);
1901                         p = p->next;
1902                 }
1903                 if (!p)
1904                         ast_mutex_unlock(&agentlock);
1905
1906                 if (!res && (max_login_tries==0 || tries < max_login_tries))
1907                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1908         }
1909                 
1910         LOCAL_USER_REMOVE(u);
1911         if (!res)
1912                 res = ast_safe_sleep(chan, 500);
1913
1914         /* AgentLogin() exit */
1915         if (!callbackmode) {
1916                 return -1;
1917         }
1918         /* AgentCallbackLogin() exit*/
1919         else {
1920                 /* Set variables */
1921                 if (login_state > 0) {
1922                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1923                         if (login_state==1) {
1924                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1925                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1926                         }
1927                         else {
1928                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1929                         }
1930                 }
1931                 else {
1932                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1933                 }
1934                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1935                         return 0;
1936                 /* Do we need to play agent-goodbye now that we will be hanging up? */
1937                 if (play_announcement==1) {
1938                         if (!res)
1939                                 res = ast_safe_sleep(chan, 1000);
1940                         res = ast_streamfile(chan, agent_goodbye, chan->language);
1941                         if (!res)
1942                                 res = ast_waitstream(chan, "");
1943                         if (!res)
1944                                 res = ast_safe_sleep(chan, 1000);
1945                 }
1946         }
1947         /* We should never get here if next priority exists when in callbackmode */
1948         return -1;
1949 }
1950
1951 static int login_exec(struct ast_channel *chan, void *data)
1952 {
1953         return __login_exec(chan, data, 0);
1954 }
1955
1956 static int callback_exec(struct ast_channel *chan, void *data)
1957 {
1958         return __login_exec(chan, data, 1);
1959 }
1960
1961 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1962 {
1963         int exitifnoagentid = 0;
1964         int nowarnings = 0;
1965         int changeoutgoing = 0;
1966         int res = 0;
1967         char agent[AST_MAX_AGENT], *tmp;
1968
1969         if (data) {
1970                 if (strchr(data, 'd'))
1971                         exitifnoagentid = 1;
1972                 if (strchr(data, 'n'))
1973                         nowarnings = 1;
1974                 if (strchr(data, 'c'))
1975                         changeoutgoing = 1;
1976         }
1977         if (chan->cid.cid_num) {
1978                 char agentvar[AST_MAX_BUF];
1979                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1980                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1981                         struct agent_pvt *p = agents;
1982                         strncpy(agent, tmp, sizeof(agent) - 1);
1983                         ast_mutex_lock(&agentlock);
1984                         while (p) {
1985                                 if (!strcasecmp(p->agent, tmp)) {
1986                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1987                                         __agent_start_monitoring(chan, p, 1);
1988                                         break;
1989                                 }
1990                                 p = p->next;
1991                         }
1992                         ast_mutex_unlock(&agentlock);
1993                         
1994                 } else {
1995                         res = -1;
1996                         if (!nowarnings)
1997                                 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);
1998                 }
1999         } else {
2000                 res = -1;
2001                 if (!nowarnings)
2002                         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");
2003         }
2004         /* check if there is n + 101 priority */
2005         if (res) {
2006                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2007                         chan->priority+=100;
2008                         if (option_verbose > 2)
2009                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2010                }
2011                 else if (exitifnoagentid)
2012                         return res;
2013         }
2014         return 0;
2015 }
2016
2017 /* Dump AgentCallbackLogin agents to the database for persistence
2018  *  (basically copied from dump_queue_members() in apps/app_queue.c)
2019  */
2020
2021 static void dump_agents(void)
2022 {
2023         struct agent_pvt *cur_agent = NULL;
2024         cur_agent = agents;
2025         while (cur_agent) {
2026                 if (cur_agent->chan != NULL) {
2027                         cur_agent = cur_agent->next;
2028                         continue;
2029                 }
2030                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2031                         if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan)) {
2032                                 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2033                         } else {
2034                                 if (option_debug) {
2035                                         ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n",
2036                                                         cur_agent->agent, cur_agent->loginchan);
2037                                 }
2038                         }
2039                         
2040                 } else {
2041                         /* Delete -  no agent or there is an error */
2042                         ast_db_del(pa_family, cur_agent->agent);
2043                 }
2044                 cur_agent = cur_agent->next;
2045         }
2046 }
2047
2048 /* Reload the persistent agents from astdb */
2049 static void reload_agents(void)
2050 {
2051         char *pa_agent_num;
2052         struct ast_db_entry *pa_db_tree = NULL;
2053         int pa_family_len = 0;
2054         struct agent_pvt *cur_agent = NULL;
2055         char agent_data[80];
2056
2057         pa_db_tree = ast_db_gettree(pa_family, NULL);
2058
2059         pa_family_len = strlen(pa_family);
2060         ast_mutex_lock(&agentlock);
2061         while (pa_db_tree) {
2062                 pa_agent_num = pa_db_tree->key + pa_family_len + 2;
2063                 cur_agent = agents;
2064                 while (cur_agent) {
2065                         ast_mutex_lock(&cur_agent->lock);
2066
2067                         if (strcmp(pa_agent_num, cur_agent->agent) == 0)
2068                                 break;
2069
2070                         ast_mutex_unlock(&cur_agent->lock);
2071                         cur_agent = cur_agent->next;
2072                 }
2073                 if (!cur_agent) {
2074                         ast_db_del(pa_family, pa_agent_num);
2075                         pa_db_tree = pa_db_tree->next;
2076                         continue;
2077                 } else
2078                         ast_mutex_unlock(&cur_agent->lock);
2079                 if (!ast_db_get(pa_family, pa_agent_num, agent_data, 80)) {
2080                         if (option_debug) {
2081                                 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n",
2082                                                 cur_agent->agent, agent_data);
2083                         }
2084                         strncpy(cur_agent->loginchan,agent_data,80);
2085                         if (cur_agent->loginstart == 0)
2086                                 time(&cur_agent->loginstart);
2087                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2088                 }
2089                 pa_db_tree = pa_db_tree->next;
2090         }
2091         ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2092         ast_mutex_unlock(&agentlock);
2093         if (pa_db_tree) {
2094                 ast_db_freetree(pa_db_tree);
2095                 pa_db_tree = NULL;
2096         }
2097 }
2098
2099
2100 /*--- agent_devicestate: Part of PBX channel interface ---*/
2101 static int agent_devicestate(void *data)
2102 {
2103         struct agent_pvt *p;
2104         char *s;
2105         ast_group_t groupmatch;
2106         int groupoff;
2107         int waitforagent=0;
2108         int res = AST_DEVICE_INVALID;
2109         
2110         s = data;
2111         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2112                 groupmatch = (1 << groupoff);
2113         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2114                 groupmatch = (1 << groupoff);
2115                 waitforagent = 1;
2116         } else {
2117                 groupmatch = 0;
2118         }
2119
2120         /* Check actual logged in agents first */
2121         ast_mutex_lock(&agentlock);
2122         p = agents;
2123         while(p) {
2124                 ast_mutex_lock(&p->lock);
2125                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2126                         if (p->owner) {
2127                                 if (res != AST_DEVICE_INUSE)
2128                                         res = AST_DEVICE_BUSY;
2129                         } else {
2130                                 if (res == AST_DEVICE_BUSY)
2131                                         res = AST_DEVICE_INUSE;
2132                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2133                                         if (res == AST_DEVICE_INVALID)
2134                                                 res = AST_DEVICE_UNKNOWN;
2135                                 } else if (res == AST_DEVICE_INVALID)   
2136                                         res = AST_DEVICE_UNAVAILABLE;
2137                         }
2138                         if (!strcmp(data, p->agent)) {
2139                                 ast_mutex_unlock(&p->lock);
2140                                 break;
2141                         }
2142                 }
2143                 ast_mutex_unlock(&p->lock);
2144                 p = p->next;
2145         }
2146         ast_mutex_unlock(&agentlock);
2147         return res;
2148 }
2149
2150 /*--- load_module: Initialize channel module ---*/
2151 int load_module()
2152 {
2153         /* Make sure we can register our agent channel type */
2154         if (ast_channel_register_ex(channeltype, tdesc, capability, agent_request, agent_devicestate)) {
2155                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2156                 return -1;
2157         }
2158         /* Dialplan applications */
2159         ast_register_application(app, login_exec, synopsis, descrip);
2160         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2161         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2162         /* Manager command */
2163         ast_manager_register2("Agents", 0, action_agents, "Agents", mandescr_agents);
2164         /* CLI Application */
2165         ast_cli_register(&cli_show_agents);
2166         ast_cli_register(&cli_agent_logoff);
2167         /* Read in the config */
2168         read_agent_config();
2169         if (persistent_agents)
2170                 reload_agents();
2171         return 0;
2172 }
2173
2174 int reload()
2175 {
2176         read_agent_config();
2177         if (persistent_agents)
2178                 reload_agents();
2179         return 0;
2180 }
2181
2182 int unload_module()
2183 {
2184         struct agent_pvt *p;
2185         /* First, take us out of the channel loop */
2186         /* Unregister CLI application */
2187         ast_cli_unregister(&cli_show_agents);
2188         ast_cli_unregister(&cli_agent_logoff);
2189         /* Unregister dialplan applications */
2190         ast_unregister_application(app);
2191         ast_unregister_application(app2);
2192         ast_unregister_application(app3);
2193         /* Unregister manager command */
2194         ast_manager_unregister("Agents");
2195         /* Unregister channel */
2196         ast_channel_unregister(channeltype);
2197         if (!ast_mutex_lock(&agentlock)) {
2198                 /* Hangup all interfaces if they have an owner */
2199                 p = agents;
2200                 while(p) {
2201                         if (p->owner)
2202                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2203                         p = p->next;
2204                 }
2205                 agents = NULL;
2206                 ast_mutex_unlock(&agentlock);
2207         } else {
2208                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2209                 return -1;
2210         }               
2211         return 0;
2212 }
2213
2214 int usecount()
2215 {
2216         int res;
2217         ast_mutex_lock(&usecnt_lock);
2218         res = usecnt;
2219         ast_mutex_unlock(&usecnt_lock);
2220         return res;
2221 }
2222
2223 char *key()
2224 {
2225         return ASTERISK_GPL_KEY;
2226 }
2227
2228 char *description()
2229 {
2230         return desc;
2231 }
2232