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