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