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