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