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