b003bf8b5531555cae58c11c373afa307b7ff397
[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) {
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) {
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                         if (persistent_agents)
1367                                 dump_agents();
1368                         break;
1369                 }
1370         }
1371         return RESULT_SUCCESS;
1372 }
1373
1374 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1375 {
1376         struct agent_pvt *p;
1377         char name[AST_MAX_AGENT];
1378         int which = 0;
1379
1380         if (pos == 2) {
1381                 for (p=agents; p; p=p->next) {
1382                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1383                         if (!strncasecmp(word, name, strlen(word))) {
1384                                 if (++which > state) {
1385                                         return strdup(name);
1386                                 }
1387                         }
1388                 }
1389         } else if (pos == 3 && state == 0) {
1390                 return strdup("soft");
1391         }
1392         return NULL;
1393 }
1394
1395 /*--- agents_show: Show agents in cli ---*/
1396 static int agents_show(int fd, int argc, char **argv)
1397 {
1398         struct agent_pvt *p;
1399         char username[AST_MAX_BUF];
1400         char location[AST_MAX_BUF] = "";
1401         char talkingto[AST_MAX_BUF] = "";
1402         char moh[AST_MAX_BUF];
1403
1404         if (argc != 2)
1405                 return RESULT_SHOWUSAGE;
1406         ast_mutex_lock(&agentlock);
1407         p = agents;
1408         while(p) {
1409                 ast_mutex_lock(&p->lock);
1410                 if (p->pending) {
1411                         if (p->group)
1412                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1413                         else
1414                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1415                 } else {
1416                         if (!ast_strlen_zero(p->name))
1417                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1418                         else
1419                                 username[0] = '\0';
1420                         if (p->chan) {
1421                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1422                                 if (p->owner && ast_bridged_channel(p->owner)) {
1423                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1424                                 } else {
1425                                         strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1426                                 }
1427                         } else if (!ast_strlen_zero(p->loginchan)) {
1428                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1429                                 talkingto[0] = '\0';
1430                                 if (p->acknowledged)
1431                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1432                         } else {
1433                                 strncpy(location, "not logged in", sizeof(location) - 1);
1434                                 talkingto[0] = '\0';
1435                         }
1436                         if (!ast_strlen_zero(p->moh))
1437                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1438                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1439                                         username, location, talkingto, moh);
1440                 }
1441                 ast_mutex_unlock(&p->lock);
1442                 p = p->next;
1443         }
1444         ast_mutex_unlock(&agentlock);
1445         return RESULT_SUCCESS;
1446 }
1447
1448 static char show_agents_usage[] = 
1449 "Usage: show agents\n"
1450 "       Provides summary information on agents.\n";
1451
1452 static char agent_logoff_usage[] =
1453 "Usage: agent logoff <channel> [soft]\n"
1454 "       Sets an agent as no longer logged in.\n"
1455 "       If 'soft' is specified, do not hangup existing calls.\n";
1456
1457 static struct ast_cli_entry cli_show_agents = {
1458         { "show", "agents", NULL }, agents_show, 
1459         "Show status of agents", show_agents_usage, NULL };
1460
1461 static struct ast_cli_entry cli_agent_logoff = {
1462         { "agent", "logoff", NULL }, agent_logoff_cmd, 
1463         "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1464
1465 STANDARD_LOCAL_USER;
1466 LOCAL_USER_DECL;
1467
1468 /*--- __login_exec: Log in agent application ---*/
1469 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1470 {
1471         int res=0;
1472         int tries = 0;
1473         int max_login_tries = maxlogintries;
1474         struct agent_pvt *p;
1475         struct localuser *u;
1476         struct timeval tv;
1477         int login_state = 0;
1478         char user[AST_MAX_AGENT] = "";
1479         char pass[AST_MAX_AGENT];
1480         char agent[AST_MAX_AGENT] = "";
1481         char xpass[AST_MAX_AGENT] = "";
1482         char *errmsg;
1483         char info[512];
1484         char *opt_user = NULL;
1485         char *options = NULL;
1486         char option;
1487         char badoption[2];
1488         char *tmpoptions = NULL;
1489         char *context = NULL;
1490         char *exten = NULL;
1491         int play_announcement = 1;
1492         char agent_goodbye[AST_MAX_FILENAME_LEN];
1493         int update_cdr = updatecdr;
1494         char *filename = "agent-loginok";
1495         
1496         strcpy(agent_goodbye, agentgoodbye);
1497         LOCAL_USER_ADD(u);
1498
1499         /* Parse the arguments XXX Check for failure XXX */
1500         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1501         opt_user = info;
1502         /* Set Channel Specific Login Overrides */
1503         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1504                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1505                 if (max_login_tries < 0)
1506                         max_login_tries = 0;
1507                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1508                 if (option_verbose > 2)
1509                         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);
1510         }
1511         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1512                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1513                         update_cdr = 1;
1514                 else
1515                         update_cdr = 0;
1516                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1517                 if (option_verbose > 2)
1518                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1519         }
1520         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1521                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1522                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1523                 if (option_verbose > 2)
1524                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1525         }
1526         /* End Channel Specific Login Overrides */
1527         /* Read command line options */
1528          if( opt_user ) {
1529                 options = strchr(opt_user, '|');
1530                 if (options) {
1531                         *options = '\0';
1532                         options++;
1533                         if (callbackmode) {
1534                                 context = strchr(options, '@');
1535                                 if (context) {
1536                                         *context = '\0';
1537                                         context++;
1538                                 }
1539                                 exten = options;
1540                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1541                                 if (!*exten)
1542                                         exten = NULL;
1543                         }
1544                 }
1545                 if (options) {
1546                         while (*options) {
1547                                 option = (char)options[0];
1548                                 if ((option >= 0) && (option <= '9'))
1549                                 {
1550                                         options++;
1551                                         continue;
1552                                 }
1553                                 if (option=='s')
1554                                         play_announcement = 0;
1555                                 else {
1556                                         badoption[0] = option;
1557                                         badoption[1] = '\0';
1558                                         tmpoptions=badoption;
1559                                         if (option_verbose > 2)
1560                                                 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1561                                 }
1562                                 options++;
1563                         }
1564                 }
1565         }
1566         /* End command line options */
1567
1568         if (chan->_state != AST_STATE_UP)
1569                 res = ast_answer(chan);
1570         if (!res) {
1571                 if( opt_user && !ast_strlen_zero(opt_user))
1572                         strncpy( user, opt_user, AST_MAX_AGENT - 1);
1573                 else
1574                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1575         }
1576         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1577                 tries++;
1578                 /* Check for password */
1579                 ast_mutex_lock(&agentlock);
1580                 p = agents;
1581                 while(p) {
1582                         if (!strcmp(p->agent, user) && !p->pending)
1583                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1584                         p = p->next;
1585                 }
1586                 ast_mutex_unlock(&agentlock);
1587                 if (!res) {
1588                         if (!ast_strlen_zero(xpass))
1589                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1590                         else
1591                                 pass[0] = '\0';
1592                 }
1593                 errmsg = "agent-incorrect";
1594
1595 #if 0
1596                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1597 #endif          
1598
1599                 /* Check again for accuracy */
1600                 ast_mutex_lock(&agentlock);
1601                 p = agents;
1602                 while(p) {
1603                         ast_mutex_lock(&p->lock);
1604                         if (!strcmp(p->agent, user) &&
1605                                 !strcmp(p->password, pass) && !p->pending) {
1606                                         login_state = 1; /* Successful Login */
1607                                         /* Set Channel Specific Agent Overides */
1608                                         if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1609                                                 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1610                                                         p->ackcall = 2;
1611                                                 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1612                                                         p->ackcall = 1;
1613                                                 else
1614                                                         p->ackcall = 0;
1615                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1616                                                 if (option_verbose > 2)
1617                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1618                                         }
1619                                         if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1620                                                 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1621                                                 if (p->autologoff < 0)
1622                                                         p->autologoff = 0;
1623                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1624                                                 if (option_verbose > 2)
1625                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1626                                         }
1627                                         if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1628                                                 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1629                                                 if (p->wrapuptime < 0)
1630                                                         p->wrapuptime = 0;
1631                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1632                                                 if (option_verbose > 2)
1633                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1634                                         }
1635                                         /* End Channel Specific Agent Overides */
1636                                         if (!p->chan) {
1637                                                 char last_loginchan[80] = "";
1638                                                 long logintime;
1639                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1640
1641                                                 if (callbackmode) {
1642                                                         char tmpchan[AST_MAX_BUF] = "";
1643                                                         int pos = 0;
1644                                                         /* Retrieve login chan */
1645                                                         for (;;) {
1646                                                                 if (exten) {
1647                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1648                                                                         res = 0;
1649                                                                 } else
1650                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1651                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1652                                                                                         1, NULL))
1653                                                                         break;
1654                                                                 if (exten) {
1655                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1656                                                                         exten = NULL;
1657                                                                         pos = 0;
1658                                                                 } else {
1659                                                                         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);
1660                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1661                                                                         if (!res)
1662                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1663                                                                         if (res > 0) {
1664                                                                                 tmpchan[0] = res;
1665                                                                                 tmpchan[1] = '\0';
1666                                                                                 pos = 1;
1667                                                                         } else {
1668                                                                                 tmpchan[0] = '\0';
1669                                                                                 pos = 0;
1670                                                                         }
1671                                                                 }
1672                                                         }
1673                                                         exten = tmpchan;
1674                                                         if (!res) {
1675                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1676                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1677                                                                 else {
1678                                                                         strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1679                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1680                                                                 }
1681                                                                 if (ast_strlen_zero(p->loginchan)) {
1682                                                                         login_state = 2;
1683                                                                         filename = "agent-loggedoff";
1684                                                                 }
1685                                                                 p->acknowledged = 0;
1686                                                                 /* store/clear the global variable that stores agentid based on the callerid */
1687                                                                 if (chan->cid.cid_num) {
1688                                                                         char agentvar[AST_MAX_BUF];
1689                                                                         snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1690                                                                         if (ast_strlen_zero(p->loginchan))
1691                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1692                                                                         else
1693                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1694                                                                 }
1695                                                                 if(update_cdr && chan->cdr)
1696                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1697
1698                                                         }
1699                                                 } else {
1700                                                         p->loginchan[0] = '\0';
1701                                                         p->acknowledged = 0;
1702                                                 }
1703                                                 ast_mutex_unlock(&p->lock);
1704                                                 ast_mutex_unlock(&agentlock);
1705                                                 if( !res && play_announcement==1 )
1706                                                         res = ast_streamfile(chan, filename, chan->language);
1707                                                 if (!res)
1708                                                         ast_waitstream(chan, "");
1709                                                 ast_mutex_lock(&agentlock);
1710                                                 ast_mutex_lock(&p->lock);
1711                                                 if (!res) {
1712                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1713                                                         if (res)
1714                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1715                                                 }
1716                                                 if (!res) {
1717                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1718                                                         if (res)
1719                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1720                                                 }
1721                                                 /* Check once more just in case */
1722                                                 if (p->chan)
1723                                                         res = -1;
1724                                                 if (callbackmode && !res) {
1725                                                         /* Just say goodbye and be done with it */
1726                                                         if (!ast_strlen_zero(p->loginchan)) {
1727                                                                 if (p->loginstart == 0)
1728                                                                         time(&p->loginstart);
1729                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1730                                                                         "Agent: %s\r\n"
1731                                                                         "Loginchan: %s\r\n"
1732                                                                         "Uniqueid: %s\r\n",
1733                                                                         p->agent, p->loginchan, chan->uniqueid);
1734                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1735                                                                 if (option_verbose > 1)
1736                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1737                                                                 ast_device_state_changed("Agent/%s", p->agent);
1738                                                         } else {
1739                                                                 logintime = time(NULL) - p->loginstart;
1740                                                                 p->loginstart = 0;
1741                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1742                                                                         "Agent: %s\r\n"
1743                                                                         "Loginchan: %s\r\n"
1744                                                                         "Logintime: %ld\r\n"
1745                                                                         "Uniqueid: %s\r\n",
1746                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1747                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1748                                                                 if (option_verbose > 1)
1749                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1750                                                                 ast_device_state_changed("Agent/%s", p->agent);
1751                                                         }
1752                                                         ast_mutex_unlock(&agentlock);
1753                                                         if (!res)
1754                                                                 res = ast_safe_sleep(chan, 500);
1755                                                         ast_mutex_unlock(&p->lock);
1756                                                         if (persistent_agents)
1757                                                                 dump_agents();
1758                                                 } else if (!res) {
1759 #ifdef HONOR_MUSIC_CLASS
1760                                                         /* check if the moh class was changed with setmusiconhold */
1761                                                         if (*(chan->musicclass))
1762                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1763 #endif                                                          
1764                                                         ast_moh_start(chan, p->moh);
1765                                                         if (p->loginstart == 0)
1766                                                                 time(&p->loginstart);
1767                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1768                                                                 "Agent: %s\r\n"
1769                                                                 "Channel: %s\r\n"
1770                                                                 "Uniqueid: %s\r\n",
1771                                                                 p->agent, chan->name, chan->uniqueid);
1772                                                         if (update_cdr && chan->cdr)
1773                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1774                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1775                                                         if (option_verbose > 1)
1776                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1777                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1778                                                         /* Login this channel and wait for it to
1779                                                            go away */
1780                                                         p->chan = chan;
1781                                                         if (p->ackcall > 1)
1782                                                                 check_beep(p, 0);
1783                                                         else
1784                                                                 check_availability(p, 0);
1785                                                         ast_mutex_unlock(&p->lock);
1786                                                         ast_mutex_unlock(&agentlock);
1787                                                         ast_device_state_changed("Agent/%s", p->agent);
1788                                                         while (res >= 0) {
1789                                                                 ast_mutex_lock(&p->lock);
1790                                                                 if (p->chan != chan)
1791                                                                         res = -1;
1792                                                                 ast_mutex_unlock(&p->lock);
1793                                                                 /* Yield here so other interested threads can kick in. */
1794                                                                 sched_yield();
1795                                                                 if (res)
1796                                                                         break;
1797
1798                                                                 ast_mutex_lock(&agentlock);
1799                                                                 ast_mutex_lock(&p->lock);
1800                                                                 if (p->lastdisc.tv_sec) {
1801                                                                         gettimeofday(&tv, NULL);
1802                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1803                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1804                                                                                         if (option_debug)
1805                                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1806                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1807                                                                                 if (p->ackcall > 1)
1808                                                                                         check_beep(p, 0);
1809                                                                                 else
1810                                                                                         check_availability(p, 0);
1811                                                                         }
1812                                                                 }
1813                                                                 ast_mutex_unlock(&p->lock);
1814                                                                 ast_mutex_unlock(&agentlock);
1815                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1816                                                                 ast_mutex_lock( &p->app_lock );
1817                                                                 ast_mutex_lock(&p->lock);
1818                                                                 p->owning_app = pthread_self();
1819                                                                 ast_mutex_unlock(&p->lock);
1820                                                                 if (p->ackcall > 1) 
1821                                                                         res = agent_ack_sleep(p);
1822                                                                 else
1823                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1824                                                                                                         agent_cont_sleep, p );
1825                                                                 ast_mutex_unlock( &p->app_lock );
1826                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1827                                                                         ast_mutex_lock(&agentlock);
1828                                                                         ast_mutex_lock(&p->lock);
1829                                                                         check_availability(p, 0);
1830                                                                         ast_mutex_unlock(&p->lock);
1831                                                                         ast_mutex_unlock(&agentlock);
1832                                                                         res = 0;
1833                                                                 }
1834                                                                 sched_yield();
1835                                                         }
1836                                                         ast_mutex_lock(&p->lock);
1837                                                         if (res && p->owner) 
1838                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1839                                                         /* Log us off if appropriate */
1840                                                         if (p->chan == chan)
1841                                                                 p->chan = NULL;
1842                                                         p->acknowledged = 0;
1843                                                         logintime = time(NULL) - p->loginstart;
1844                                                         p->loginstart = 0;
1845                                                         ast_mutex_unlock(&p->lock);
1846                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1847                                                                 "Agent: %s\r\n"
1848                                                                 "Logintime: %ld\r\n"
1849                                                                 "Uniqueid: %s\r\n",
1850                                                                 p->agent, logintime, chan->uniqueid);
1851                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1852                                                         if (option_verbose > 1)
1853                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1854                                                         /* If there is no owner, go ahead and kill it now */
1855                                                         ast_device_state_changed("Agent/%s", p->agent);
1856                                                         if (p->dead && !p->owner) {
1857                                                                 ast_mutex_destroy(&p->lock);
1858                                                                 ast_mutex_destroy(&p->app_lock);
1859                                                                 free(p);
1860                                                         }
1861                                                 }
1862                                                 else {
1863                                                         ast_mutex_unlock(&p->lock);
1864                                                         p = NULL;
1865                                                 }
1866                                                 res = -1;
1867                                         } else {
1868                                                 ast_mutex_unlock(&p->lock);
1869                                                 errmsg = "agent-alreadyon";
1870                                                 p = NULL;
1871                                         }
1872                                         break;
1873                         }
1874                         ast_mutex_unlock(&p->lock);
1875                         p = p->next;
1876                 }
1877                 if (!p)
1878                         ast_mutex_unlock(&agentlock);
1879
1880                 if (!res && (max_login_tries==0 || tries < max_login_tries))
1881                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1882         }
1883                 
1884         LOCAL_USER_REMOVE(u);
1885         if (!res)
1886                 res = ast_safe_sleep(chan, 500);
1887
1888         /* AgentLogin() exit */
1889         if (!callbackmode) {
1890                 return -1;
1891         }
1892         /* AgentCallbackLogin() exit*/
1893         else {
1894                 /* Set variables */
1895                 if (login_state > 0) {
1896                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1897                         if (login_state==1) {
1898                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1899                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1900                         }
1901                         else {
1902                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1903                         }
1904                 }
1905                 else {
1906                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1907                 }
1908                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1909                         return 0;
1910                 /* Do we need to play agent-goodbye now that we will be hanging up? */
1911                 if (play_announcement==1) {
1912                         if (!res)
1913                                 res = ast_safe_sleep(chan, 1000);
1914                         res = ast_streamfile(chan, agent_goodbye, chan->language);
1915                         if (!res)
1916                                 res = ast_waitstream(chan, "");
1917                         if (!res)
1918                                 res = ast_safe_sleep(chan, 1000);
1919                 }
1920         }
1921         /* We should never get here if next priority exists when in callbackmode */
1922         return -1;
1923 }
1924
1925 static int login_exec(struct ast_channel *chan, void *data)
1926 {
1927         return __login_exec(chan, data, 0);
1928 }
1929
1930 static int callback_exec(struct ast_channel *chan, void *data)
1931 {
1932         return __login_exec(chan, data, 1);
1933 }
1934
1935 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1936 {
1937         int exitifnoagentid = 0;
1938         int nowarnings = 0;
1939         int changeoutgoing = 0;
1940         int res = 0;
1941         char agent[AST_MAX_AGENT], *tmp;
1942
1943         if (data) {
1944                 if (strchr(data, 'd'))
1945                         exitifnoagentid = 1;
1946                 if (strchr(data, 'n'))
1947                         nowarnings = 1;
1948                 if (strchr(data, 'c'))
1949                         changeoutgoing = 1;
1950         }
1951         if (chan->cid.cid_num) {
1952                 char agentvar[AST_MAX_BUF];
1953                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1954                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1955                         struct agent_pvt *p = agents;
1956                         strncpy(agent, tmp, sizeof(agent) - 1);
1957                         ast_mutex_lock(&agentlock);
1958                         while (p) {
1959                                 if (!strcasecmp(p->agent, tmp)) {
1960                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1961                                         __agent_start_monitoring(chan, p, 1);
1962                                         break;
1963                                 }
1964                                 p = p->next;
1965                         }
1966                         ast_mutex_unlock(&agentlock);
1967                         
1968                 } else {
1969                         res = -1;
1970                         if (!nowarnings)
1971                                 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);
1972                 }
1973         } else {
1974                 res = -1;
1975                 if (!nowarnings)
1976                         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");
1977         }
1978         /* check if there is n + 101 priority */
1979         if (res) {
1980                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1981                         chan->priority+=100;
1982                         if (option_verbose > 2)
1983                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1984                }
1985                 else if (exitifnoagentid)
1986                         return res;
1987         }
1988         return 0;
1989 }
1990
1991 /* Dump AgentCallbackLogin agents to the database for persistence
1992  */
1993
1994 static void dump_agents(void)
1995 {
1996         struct agent_pvt *cur_agent = NULL;
1997
1998         for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
1999                 if (cur_agent->chan)
2000                         continue;
2001
2002                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2003                         if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan))
2004                                 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2005                         else if (option_debug)
2006                                 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2007                 } else {
2008                         /* Delete -  no agent or there is an error */
2009                         ast_db_del(pa_family, cur_agent->agent);
2010                 }
2011         }
2012 }
2013
2014 /* Reload the persistent agents from astdb */
2015 static void reload_agents(void)
2016 {
2017         char *agent_num;
2018         struct ast_db_entry *db_tree;
2019         struct ast_db_entry *entry;
2020         struct agent_pvt *cur_agent;
2021         char agent_data[80];
2022
2023         db_tree = ast_db_gettree(pa_family, NULL);
2024
2025         ast_mutex_lock(&agentlock);
2026         for (entry = db_tree; entry; entry = entry->next) {
2027                 agent_num = entry->key + strlen(pa_family) + 2;
2028                 cur_agent = agents;
2029                 while (cur_agent) {
2030                         ast_mutex_lock(&cur_agent->lock);
2031                         if (strcmp(agent_num, cur_agent->agent) == 0)
2032                                 break;
2033                         ast_mutex_unlock(&cur_agent->lock);
2034                         cur_agent = cur_agent->next;
2035                 }
2036                 if (!cur_agent) {
2037                         ast_db_del(pa_family, agent_num);
2038                         continue;
2039                 } else
2040                         ast_mutex_unlock(&cur_agent->lock);
2041                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2042                         if (option_debug)
2043                                 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2044                         strncpy(cur_agent->loginchan, agent_data, sizeof(cur_agent->loginchan)-1);
2045                         if (cur_agent->loginstart == 0)
2046                                 time(&cur_agent->loginstart);
2047                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2048                 }
2049         }
2050         ast_mutex_unlock(&agentlock);
2051         if (db_tree) {
2052                 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2053                 ast_db_freetree(db_tree);
2054         }
2055 }
2056
2057
2058 /*--- agent_devicestate: Part of PBX channel interface ---*/
2059 static int agent_devicestate(void *data)
2060 {
2061         struct agent_pvt *p;
2062         char *s;
2063         ast_group_t groupmatch;
2064         int groupoff;
2065         int waitforagent=0;
2066         int res = AST_DEVICE_INVALID;
2067         
2068         s = data;
2069         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2070                 groupmatch = (1 << groupoff);
2071         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2072                 groupmatch = (1 << groupoff);
2073                 waitforagent = 1;
2074         } else {
2075                 groupmatch = 0;
2076         }
2077
2078         /* Check actual logged in agents first */
2079         ast_mutex_lock(&agentlock);
2080         p = agents;
2081         while(p) {
2082                 ast_mutex_lock(&p->lock);
2083                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2084                         if (p->owner) {
2085                                 if (res != AST_DEVICE_INUSE)
2086                                         res = AST_DEVICE_BUSY;
2087                         } else {
2088                                 if (res == AST_DEVICE_BUSY)
2089                                         res = AST_DEVICE_INUSE;
2090                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2091                                         if (res == AST_DEVICE_INVALID)
2092                                                 res = AST_DEVICE_UNKNOWN;
2093                                 } else if (res == AST_DEVICE_INVALID)   
2094                                         res = AST_DEVICE_UNAVAILABLE;
2095                         }
2096                         if (!strcmp(data, p->agent)) {
2097                                 ast_mutex_unlock(&p->lock);
2098                                 break;
2099                         }
2100                 }
2101                 ast_mutex_unlock(&p->lock);
2102                 p = p->next;
2103         }
2104         ast_mutex_unlock(&agentlock);
2105         return res;
2106 }
2107
2108 /*--- load_module: Initialize channel module ---*/
2109 int load_module()
2110 {
2111         /* Make sure we can register our agent channel type */
2112         if (ast_channel_register(&agent_tech)) {
2113                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2114                 return -1;
2115         }
2116         /* Dialplan applications */
2117         ast_register_application(app, login_exec, synopsis, descrip);
2118         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2119         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2120         /* Manager command */
2121         ast_manager_register2("Agents", 0, action_agents, "Lists agents and their status", mandescr_agents);
2122         /* CLI Application */
2123         ast_cli_register(&cli_show_agents);
2124         ast_cli_register(&cli_agent_logoff);
2125         /* Read in the config */
2126         read_agent_config();
2127         if (persistent_agents)
2128                 reload_agents();
2129         return 0;
2130 }
2131
2132 int reload()
2133 {
2134         read_agent_config();
2135         if (persistent_agents)
2136                 reload_agents();
2137         return 0;
2138 }
2139
2140 int unload_module()
2141 {
2142         struct agent_pvt *p;
2143         /* First, take us out of the channel loop */
2144         /* Unregister CLI application */
2145         ast_cli_unregister(&cli_show_agents);
2146         ast_cli_unregister(&cli_agent_logoff);
2147         /* Unregister dialplan applications */
2148         ast_unregister_application(app);
2149         ast_unregister_application(app2);
2150         ast_unregister_application(app3);
2151         /* Unregister manager command */
2152         ast_manager_unregister("Agents");
2153         /* Unregister channel */
2154         ast_channel_unregister(&agent_tech);
2155         if (!ast_mutex_lock(&agentlock)) {
2156                 /* Hangup all interfaces if they have an owner */
2157                 p = agents;
2158                 while(p) {
2159                         if (p->owner)
2160                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2161                         p = p->next;
2162                 }
2163                 agents = NULL;
2164                 ast_mutex_unlock(&agentlock);
2165         } else {
2166                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2167                 return -1;
2168         }               
2169         return 0;
2170 }
2171
2172 int usecount()
2173 {
2174         int res;
2175         ast_mutex_lock(&usecnt_lock);
2176         res = usecnt;
2177         ast_mutex_unlock(&usecnt_lock);
2178         return res;
2179 }
2180
2181 char *key()
2182 {
2183         return ASTERISK_GPL_KEY;
2184 }
2185
2186 char *description()
2187 {
2188         return (char *) desc;
2189 }
2190