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