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