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