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