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