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