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