ensure that agent channels don't get seized during login (issue #5020)
[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
1753                                 /* Ensure we can't be gotten until we're done */
1754                                 gettimeofday(&p->lastdisc, NULL);
1755                                 p->lastdisc.tv_sec++;
1756
1757                                 /* Set Channel Specific Agent Overides */
1758                                 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1759                                         if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1760                                                 p->ackcall = 2;
1761                                         else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1762                                                 p->ackcall = 1;
1763                                         else
1764                                                 p->ackcall = 0;
1765                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1766                                         if (option_verbose > 2)
1767                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1768                                 }
1769                                 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1770                                         p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1771                                         if (p->autologoff < 0)
1772                                                 p->autologoff = 0;
1773                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1774                                         if (option_verbose > 2)
1775                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1776                                 }
1777                                 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1778                                         p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1779                                         if (p->wrapuptime < 0)
1780                                                 p->wrapuptime = 0;
1781                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1782                                         if (option_verbose > 2)
1783                                                 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1784                                 }
1785                                 /* End Channel Specific Agent Overides */
1786                                 if (!p->chan) {
1787                                         char last_loginchan[80] = "";
1788                                         long logintime;
1789                                         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1790
1791                                         if (callbackmode) {
1792                                                 char tmpchan[AST_MAX_BUF] = "";
1793                                                 int pos = 0;
1794                                                 /* Retrieve login chan */
1795                                                 for (;;) {
1796                                                         if (exten) {
1797                                                                 ast_copy_string(tmpchan, exten, sizeof(tmpchan));
1798                                                                 res = 0;
1799                                                         } else
1800                                                                 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1801                                                         if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1802                                                                                                              1, NULL))
1803                                                                 break;
1804                                                         if (exten) {
1805                                                                 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1806                                                                 exten = NULL;
1807                                                                 pos = 0;
1808                                                         } else {
1809                                                                 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);
1810                                                                 res = ast_streamfile(chan, "invalid", chan->language);
1811                                                                 if (!res)
1812                                                                         res = ast_waitstream(chan, AST_DIGIT_ANY);
1813                                                                 if (res > 0) {
1814                                                                         tmpchan[0] = res;
1815                                                                         tmpchan[1] = '\0';
1816                                                                         pos = 1;
1817                                                                 } else {
1818                                                                         tmpchan[0] = '\0';
1819                                                                         pos = 0;
1820                                                                 }
1821                                                         }
1822                                                 }
1823                                                 exten = tmpchan;
1824                                                 if (!res) {
1825                                                         set_agentbycallerid(p->logincallerid, NULL);
1826                                                         if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1827                                                                 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1828                                                         else {
1829                                                                 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1830                                                                 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1831                                                         }
1832                                                         p->acknowledged = 0;
1833                                                         if (ast_strlen_zero(p->loginchan)) {
1834                                                                 login_state = 2;
1835                                                                 filename = "agent-loggedoff";
1836                                                         } else {
1837                                                                 if (chan->cid.cid_num) {
1838                                                                         ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1839                                                                         set_agentbycallerid(p->logincallerid, p->agent);
1840                                                                 } else
1841                                                                         p->logincallerid[0] = '\0';
1842                                                         }
1843
1844                                                         if(update_cdr && chan->cdr)
1845                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1846
1847                                                 }
1848                                         } else {
1849                                                 p->loginchan[0] = '\0';
1850                                                 p->logincallerid[0] = '\0';
1851                                                 p->acknowledged = 0;
1852                                         }
1853                                         ast_mutex_unlock(&p->lock);
1854                                         ast_mutex_unlock(&agentlock);
1855                                         if( !res && play_announcement==1 )
1856                                                 res = ast_streamfile(chan, filename, chan->language);
1857                                         if (!res)
1858                                                 ast_waitstream(chan, "");
1859                                         ast_mutex_lock(&agentlock);
1860                                         ast_mutex_lock(&p->lock);
1861                                         if (!res) {
1862                                                 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1863                                                 if (res)
1864                                                         ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1865                                         }
1866                                         if (!res) {
1867                                                 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1868                                                 if (res)
1869                                                         ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1870                                         }
1871                                         /* Check once more just in case */
1872                                         if (p->chan)
1873                                                 res = -1;
1874                                         if (callbackmode && !res) {
1875                                                 /* Just say goodbye and be done with it */
1876                                                 if (!ast_strlen_zero(p->loginchan)) {
1877                                                         if (p->loginstart == 0)
1878                                                                 time(&p->loginstart);
1879                                                         manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1880                                                                       "Agent: %s\r\n"
1881                                                                       "Loginchan: %s\r\n"
1882                                                                       "Uniqueid: %s\r\n",
1883                                                                       p->agent, p->loginchan, chan->uniqueid);
1884                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1885                                                         if (option_verbose > 1)
1886                                                                 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1887                                                         ast_device_state_changed("Agent/%s", p->agent);
1888                                                 } else {
1889                                                         logintime = time(NULL) - p->loginstart;
1890                                                         p->loginstart = 0;
1891                                                         manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1892                                                                       "Agent: %s\r\n"
1893                                                                       "Loginchan: %s\r\n"
1894                                                                       "Logintime: %ld\r\n"
1895                                                                       "Uniqueid: %s\r\n",
1896                                                                       p->agent, last_loginchan, logintime, chan->uniqueid);
1897                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1898                                                         if (option_verbose > 1)
1899                                                                 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1900                                                         ast_device_state_changed("Agent/%s", p->agent);
1901                                                 }
1902                                                 ast_mutex_unlock(&agentlock);
1903                                                 if (!res)
1904                                                         res = ast_safe_sleep(chan, 500);
1905                                                 ast_mutex_unlock(&p->lock);
1906                                                 if (persistent_agents)
1907                                                         dump_agents();
1908                                         } else if (!res) {
1909 #ifdef HONOR_MUSIC_CLASS
1910                                                 /* check if the moh class was changed with setmusiconhold */
1911                                                 if (*(chan->musicclass))
1912                                                         ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
1913 #endif                                                          
1914                                                 ast_moh_start(chan, p->moh);
1915                                                 if (p->loginstart == 0)
1916                                                         time(&p->loginstart);
1917                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1918                                                               "Agent: %s\r\n"
1919                                                               "Channel: %s\r\n"
1920                                                               "Uniqueid: %s\r\n",
1921                                                               p->agent, chan->name, chan->uniqueid);
1922                                                 if (update_cdr && chan->cdr)
1923                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1924                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1925                                                 if (option_verbose > 1)
1926                                                         ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1927                                                                     ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1928                                                 /* Login this channel and wait for it to
1929                                                    go away */
1930                                                 p->chan = chan;
1931                                                 if (p->ackcall > 1)
1932                                                         check_beep(p, 0);
1933                                                 else
1934                                                         check_availability(p, 0);
1935                                                 ast_mutex_unlock(&p->lock);
1936                                                 ast_mutex_unlock(&agentlock);
1937                                                 ast_device_state_changed("Agent/%s", p->agent);
1938                                                 while (res >= 0) {
1939                                                         ast_mutex_lock(&p->lock);
1940                                                         if (p->chan != chan)
1941                                                                 res = -1;
1942                                                         ast_mutex_unlock(&p->lock);
1943                                                         /* Yield here so other interested threads can kick in. */
1944                                                         sched_yield();
1945                                                         if (res)
1946                                                                 break;
1947
1948                                                         ast_mutex_lock(&agentlock);
1949                                                         ast_mutex_lock(&p->lock);
1950                                                         if (p->lastdisc.tv_sec) {
1951                                                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
1952                                                                         if (option_debug)
1953                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1954                                                                         p->lastdisc = ast_tv(0, 0);
1955                                                                         if (p->ackcall > 1)
1956                                                                                 check_beep(p, 0);
1957                                                                         else
1958                                                                                 check_availability(p, 0);
1959                                                                 }
1960                                                         }
1961                                                         ast_mutex_unlock(&p->lock);
1962                                                         ast_mutex_unlock(&agentlock);
1963                                                         /*      Synchronize channel ownership between call to agent and itself. */
1964                                                         ast_mutex_lock( &p->app_lock );
1965                                                         ast_mutex_lock(&p->lock);
1966                                                         p->owning_app = pthread_self();
1967                                                         ast_mutex_unlock(&p->lock);
1968                                                         if (p->ackcall > 1) 
1969                                                                 res = agent_ack_sleep(p);
1970                                                         else
1971                                                                 res = ast_safe_sleep_conditional( chan, 1000,
1972                                                                                                   agent_cont_sleep, p );
1973                                                         ast_mutex_unlock( &p->app_lock );
1974                                                         if ((p->ackcall > 1)  && (res == 1)) {
1975                                                                 ast_mutex_lock(&agentlock);
1976                                                                 ast_mutex_lock(&p->lock);
1977                                                                 check_availability(p, 0);
1978                                                                 ast_mutex_unlock(&p->lock);
1979                                                                 ast_mutex_unlock(&agentlock);
1980                                                                 res = 0;
1981                                                         }
1982                                                         sched_yield();
1983                                                 }
1984                                                 ast_mutex_lock(&p->lock);
1985                                                 if (res && p->owner) 
1986                                                         ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1987                                                 /* Log us off if appropriate */
1988                                                 if (p->chan == chan)
1989                                                         p->chan = NULL;
1990                                                 p->acknowledged = 0;
1991                                                 logintime = time(NULL) - p->loginstart;
1992                                                 p->loginstart = 0;
1993                                                 ast_mutex_unlock(&p->lock);
1994                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1995                                                               "Agent: %s\r\n"
1996                                                               "Logintime: %ld\r\n"
1997                                                               "Uniqueid: %s\r\n",
1998                                                               p->agent, logintime, chan->uniqueid);
1999                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2000                                                 if (option_verbose > 1)
2001                                                         ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
2002                                                 /* If there is no owner, go ahead and kill it now */
2003                                                 ast_device_state_changed("Agent/%s", p->agent);
2004                                                 if (p->dead && !p->owner) {
2005                                                         ast_mutex_destroy(&p->lock);
2006                                                         ast_mutex_destroy(&p->app_lock);
2007                                                         free(p);
2008                                                 }
2009                                         }
2010                                         else {
2011                                                 ast_mutex_unlock(&p->lock);
2012                                                 p = NULL;
2013                                         }
2014                                         res = -1;
2015                                 } else {
2016                                         ast_mutex_unlock(&p->lock);
2017                                         errmsg = "agent-alreadyon";
2018                                         p = NULL;
2019                                 }
2020                                 break;
2021                         }
2022                         ast_mutex_unlock(&p->lock);
2023                         p = p->next;
2024                 }
2025                 if (!p)
2026                         ast_mutex_unlock(&agentlock);
2027
2028                 if (!res && (max_login_tries==0 || tries < max_login_tries))
2029                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2030         }
2031                 
2032         LOCAL_USER_REMOVE(u);
2033         if (!res)
2034                 res = ast_safe_sleep(chan, 500);
2035
2036         /* AgentLogin() exit */
2037         if (!callbackmode) {
2038                 return -1;
2039         }
2040         /* AgentCallbackLogin() exit*/
2041         else {
2042                 /* Set variables */
2043                 if (login_state > 0) {
2044                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
2045                         if (login_state==1) {
2046                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
2047                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
2048                         }
2049                         else {
2050                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
2051                         }
2052                 }
2053                 else {
2054                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
2055                 }
2056                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
2057                         return 0;
2058                 /* Do we need to play agent-goodbye now that we will be hanging up? */
2059                 if (play_announcement==1) {
2060                         if (!res)
2061                                 res = ast_safe_sleep(chan, 1000);
2062                         res = ast_streamfile(chan, agent_goodbye, chan->language);
2063                         if (!res)
2064                                 res = ast_waitstream(chan, "");
2065                         if (!res)
2066                                 res = ast_safe_sleep(chan, 1000);
2067                 }
2068         }
2069         /* We should never get here if next priority exists when in callbackmode */
2070         return -1;
2071 }
2072
2073 static int login_exec(struct ast_channel *chan, void *data)
2074 {
2075         return __login_exec(chan, data, 0);
2076 }
2077
2078 static int callback_exec(struct ast_channel *chan, void *data)
2079 {
2080         return __login_exec(chan, data, 1);
2081 }
2082
2083 static int action_agent_callback_login(struct mansession *s, struct message *m)
2084 {
2085         char *agent = astman_get_header(m, "Agent");
2086         char *exten = astman_get_header(m, "Exten");
2087         char *context = astman_get_header(m, "Context");
2088         char *wrapuptime_s = astman_get_header(m, "WrapupTime");
2089         char *ackcall_s = astman_get_header(m, "AckCall");
2090         struct agent_pvt *p;
2091         int login_state = 0;
2092
2093         if (ast_strlen_zero(agent)) {
2094                 astman_send_error(s, m, "No agent specified");
2095                 return 0;
2096         }
2097
2098         if (ast_strlen_zero(exten)) {
2099                 astman_send_error(s, m, "No extension specified");
2100                 return 0;
2101         }
2102
2103         ast_mutex_lock(&agentlock);
2104         p = agents;
2105         while(p) {
2106                 if (strcmp(p->agent, agent) || p->pending) {
2107                         p = p->next;
2108                         continue;
2109                 }
2110                 if (p->chan) {
2111                         login_state = 2; /* already logged in (and on the phone)*/
2112                         break;
2113                 }
2114                 ast_mutex_lock(&p->lock);
2115                 login_state = 1; /* Successful Login */
2116                 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
2117                 
2118                 if (ast_strlen_zero(context))
2119                         snprintf(p->loginchan, sizeof(p->loginchan), "%s", exten);
2120                 else
2121                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
2122
2123                 if (wrapuptime_s && !ast_strlen_zero(wrapuptime_s)) {
2124                         p->wrapuptime = atoi(wrapuptime_s);
2125                         if (p->wrapuptime < 0)
2126                                 p->wrapuptime = 0;
2127                 }
2128
2129                 if (ast_true(ackcall_s))
2130                         p->ackcall = 1;
2131                 else
2132                         p->ackcall = 0;
2133
2134                 if (p->loginstart == 0)
2135                         time(&p->loginstart);
2136                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
2137                               "Agent: %s\r\n"
2138                               "Loginchan: %s\r\n",
2139                               p->agent, p->loginchan);
2140                 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
2141                 if (option_verbose > 1)
2142                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
2143                 ast_device_state_changed("Agent/%s", p->agent);
2144                 ast_mutex_unlock(&p->lock);
2145                 p = p->next;
2146         }
2147         ast_mutex_unlock(&agentlock);
2148
2149         if (login_state == 1)
2150                 astman_send_ack(s, m, "Agent logged in");
2151         else if (login_state == 0)
2152                 astman_send_error(s, m, "No such agent");
2153         else if (login_state == 2)
2154                 astman_send_error(s, m, "Agent already logged in");
2155
2156         return 0;
2157 }
2158 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2159 {
2160         int exitifnoagentid = 0;
2161         int nowarnings = 0;
2162         int changeoutgoing = 0;
2163         int res = 0;
2164         char agent[AST_MAX_AGENT], *tmp;
2165
2166         if (data) {
2167                 if (strchr(data, 'd'))
2168                         exitifnoagentid = 1;
2169                 if (strchr(data, 'n'))
2170                         nowarnings = 1;
2171                 if (strchr(data, 'c'))
2172                         changeoutgoing = 1;
2173         }
2174         if (chan->cid.cid_num) {
2175                 char agentvar[AST_MAX_BUF];
2176                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2177                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2178                         struct agent_pvt *p = agents;
2179                         ast_copy_string(agent, tmp, sizeof(agent));
2180                         ast_mutex_lock(&agentlock);
2181                         while (p) {
2182                                 if (!strcasecmp(p->agent, tmp)) {
2183                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2184                                         __agent_start_monitoring(chan, p, 1);
2185                                         break;
2186                                 }
2187                                 p = p->next;
2188                         }
2189                         ast_mutex_unlock(&agentlock);
2190                         
2191                 } else {
2192                         res = -1;
2193                         if (!nowarnings)
2194                                 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);
2195                 }
2196         } else {
2197                 res = -1;
2198                 if (!nowarnings)
2199                         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");
2200         }
2201         /* check if there is n + 101 priority */
2202         if (res) {
2203                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2204                         chan->priority+=100;
2205                         if (option_verbose > 2)
2206                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2207                 }
2208                 else if (exitifnoagentid)
2209                         return res;
2210         }
2211         return 0;
2212 }
2213
2214 /* Dump AgentCallbackLogin agents to the database for persistence
2215  */
2216
2217 static void dump_agents(void)
2218 {
2219         struct agent_pvt *cur_agent = NULL;
2220         char buf[256];
2221
2222         for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2223                 if (cur_agent->chan)
2224                         continue;
2225
2226                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2227                         snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2228                         if (ast_db_put(pa_family, cur_agent->agent, buf))
2229                                 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2230                         else if (option_debug)
2231                                 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2232                 } else {
2233                         /* Delete -  no agent or there is an error */
2234                         ast_db_del(pa_family, cur_agent->agent);
2235                 }
2236         }
2237 }
2238
2239 /**
2240  * Reload the persistent agents from astdb.
2241  */
2242 static void reload_agents(void)
2243 {
2244         char *agent_num;
2245         struct ast_db_entry *db_tree;
2246         struct ast_db_entry *entry;
2247         struct agent_pvt *cur_agent;
2248         char agent_data[256];
2249         char *parse;
2250         char *agent_chan;
2251         char *agent_callerid;
2252
2253         db_tree = ast_db_gettree(pa_family, NULL);
2254
2255         ast_mutex_lock(&agentlock);
2256         for (entry = db_tree; entry; entry = entry->next) {
2257                 agent_num = entry->key + strlen(pa_family) + 2;
2258                 cur_agent = agents;
2259                 while (cur_agent) {
2260                         ast_mutex_lock(&cur_agent->lock);
2261                         if (strcmp(agent_num, cur_agent->agent) == 0)
2262                                 break;
2263                         ast_mutex_unlock(&cur_agent->lock);
2264                         cur_agent = cur_agent->next;
2265                 }
2266                 if (!cur_agent) {
2267                         ast_db_del(pa_family, agent_num);
2268                         continue;
2269                 } else
2270                         ast_mutex_unlock(&cur_agent->lock);
2271                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2272                         if (option_debug)
2273                                 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2274                         parse = agent_data;
2275                         agent_chan = strsep(&parse, ";");
2276                         agent_callerid = strsep(&parse, ";");
2277                         ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2278                         if (agent_callerid) {
2279                                 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2280                                 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2281                         } else
2282                                 cur_agent->logincallerid[0] = '\0';
2283                         if (cur_agent->loginstart == 0)
2284                                 time(&cur_agent->loginstart);
2285                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2286                 }
2287         }
2288         ast_mutex_unlock(&agentlock);
2289         if (db_tree) {
2290                 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2291                 ast_db_freetree(db_tree);
2292         }
2293 }
2294
2295 /*--- agent_devicestate: Part of PBX channel interface ---*/
2296 static int agent_devicestate(void *data)
2297 {
2298         struct agent_pvt *p;
2299         char *s;
2300         ast_group_t groupmatch;
2301         int groupoff;
2302         int waitforagent=0;
2303         int res = AST_DEVICE_INVALID;
2304         
2305         s = data;
2306         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2307                 groupmatch = (1 << groupoff);
2308         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2309                 groupmatch = (1 << groupoff);
2310                 waitforagent = 1;
2311         } else {
2312                 groupmatch = 0;
2313         }
2314
2315         /* Check actual logged in agents first */
2316         ast_mutex_lock(&agentlock);
2317         p = agents;
2318         while(p) {
2319                 ast_mutex_lock(&p->lock);
2320                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2321                         if (p->owner) {
2322                                 if (res != AST_DEVICE_INUSE)
2323                                         res = AST_DEVICE_BUSY;
2324                         } else {
2325                                 if (res == AST_DEVICE_BUSY)
2326                                         res = AST_DEVICE_INUSE;
2327                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2328                                         if (res == AST_DEVICE_INVALID)
2329                                                 res = AST_DEVICE_UNKNOWN;
2330                                 } else if (res == AST_DEVICE_INVALID)   
2331                                         res = AST_DEVICE_UNAVAILABLE;
2332                         }
2333                         if (!strcmp(data, p->agent)) {
2334                                 ast_mutex_unlock(&p->lock);
2335                                 break;
2336                         }
2337                 }
2338                 ast_mutex_unlock(&p->lock);
2339                 p = p->next;
2340         }
2341         ast_mutex_unlock(&agentlock);
2342         return res;
2343 }
2344
2345 /**
2346  * Initialize the Agents module.
2347  * This funcion is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
2348  *
2349  * @returns int Always 0.
2350  */
2351 int load_module()
2352 {
2353         /* Make sure we can register our agent channel type */
2354         if (ast_channel_register(&agent_tech)) {
2355                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2356                 return -1;
2357         }
2358         /* Dialplan applications */
2359         ast_register_application(app, login_exec, synopsis, descrip);
2360         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2361         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2362         /* Manager commands */
2363         ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2364         ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2365         ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
2366         /* CLI Application */
2367         ast_cli_register(&cli_show_agents);
2368         ast_cli_register(&cli_agent_logoff);
2369         /* Read in the config */
2370         read_agent_config();
2371         if (persistent_agents)
2372                 reload_agents();
2373         return 0;
2374 }
2375
2376 int reload()
2377 {
2378         read_agent_config();
2379         if (persistent_agents)
2380                 reload_agents();
2381         return 0;
2382 }
2383
2384 int unload_module()
2385 {
2386         struct agent_pvt *p;
2387         /* First, take us out of the channel loop */
2388         /* Unregister CLI application */
2389         ast_cli_unregister(&cli_show_agents);
2390         ast_cli_unregister(&cli_agent_logoff);
2391         /* Unregister dialplan applications */
2392         ast_unregister_application(app);
2393         ast_unregister_application(app2);
2394         ast_unregister_application(app3);
2395         /* Unregister manager command */
2396         ast_manager_unregister("Agents");
2397         ast_manager_unregister("AgentLogoff");
2398         ast_manager_unregister("AgentCallbackLogin");
2399         /* Unregister channel */
2400         ast_channel_unregister(&agent_tech);
2401         if (!ast_mutex_lock(&agentlock)) {
2402                 /* Hangup all interfaces if they have an owner */
2403                 p = agents;
2404                 while(p) {
2405                         if (p->owner)
2406                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2407                         p = p->next;
2408                 }
2409                 agents = NULL;
2410                 ast_mutex_unlock(&agentlock);
2411         } else {
2412                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2413                 return -1;
2414         }               
2415         return 0;
2416 }
2417
2418 int usecount()
2419 {
2420         return usecnt;
2421 }
2422
2423 char *key()
2424 {
2425         return ASTERISK_GPL_KEY;
2426 }
2427
2428 char *description()
2429 {
2430         return (char *) desc;
2431 }
2432