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