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