add doxygen documentation (issue #5133)
[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 struct agent_pvt *agent)
694 {
695         char buf[AST_MAX_BUF];
696
697         /* if there is no Caller ID, nothing to do */
698         if (!agent->logincallerid[0])
699                 return;
700
701         snprintf(buf, sizeof(buf), "%s_%s",GETAGENTBYCALLERID, agent->logincallerid);
702         pbx_builtin_setvar_helper(NULL, buf, ast_strlen_zero(agent->loginchan) ? NULL : agent->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                                 p->loginchan[0] = '\0';
764                                 set_agentbycallerid(p);
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 #if 0
778                 ast_mutex_unlock(&p->lock);
779                 /* Release ownership of the agent to other threads (presumably running the login app). */
780                 ast_mutex_unlock(&p->app_lock);
781         } else if (p->dead) {
782                 /* Go ahead and lose it */
783                 ast_mutex_unlock(&p->lock);
784                 /* Release ownership of the agent to other threads (presumably running the login app). */
785                 ast_mutex_unlock(&p->app_lock);
786         } else {
787                 ast_mutex_unlock(&p->lock);
788                 /* Release ownership of the agent to other threads (presumably running the login app). */
789                 ast_mutex_unlock(&p->app_lock);
790         }
791 #endif  
792         ast_mutex_unlock(&p->lock);
793         ast_device_state_changed("Agent/%s", p->agent);
794
795         if (p->pending) {
796                 ast_mutex_lock(&agentlock);
797                 agent_unlink(p);
798                 ast_mutex_unlock(&agentlock);
799         }
800         if (p->abouttograb) {
801                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
802                    kill it later */
803                 p->abouttograb = 0;
804         } else if (p->dead) {
805                 ast_mutex_destroy(&p->lock);
806                 ast_mutex_destroy(&p->app_lock);
807                 free(p);
808         } else {
809                 if (p->chan) {
810                         /* Not dead -- check availability now */
811                         ast_mutex_lock(&p->lock);
812                         /* Store last disconnect time */
813                         p->lastdisc = ast_tvnow();
814                         ast_mutex_unlock(&p->lock);
815                 }
816                 /* Release ownership of the agent to other threads (presumably running the login app). */
817                 ast_mutex_unlock(&p->app_lock);
818         }
819         return 0;
820 }
821
822 static int agent_cont_sleep( void *data )
823 {
824         struct agent_pvt *p;
825         int res;
826
827         p = (struct agent_pvt *)data;
828
829         ast_mutex_lock(&p->lock);
830         res = p->app_sleep_cond;
831         if (p->lastdisc.tv_sec) {
832                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) 
833                         res = 1;
834         }
835         ast_mutex_unlock(&p->lock);
836 #if 0
837         if( !res )
838                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
839 #endif          
840         return res;
841 }
842
843 static int agent_ack_sleep( void *data )
844 {
845         struct agent_pvt *p;
846         int res=0;
847         int to = 1000;
848         struct ast_frame *f;
849
850         /* Wait a second and look for something */
851
852         p = (struct agent_pvt *)data;
853         if (p->chan) {
854                 for(;;) {
855                         to = ast_waitfor(p->chan, to);
856                         if (to < 0) {
857                                 res = -1;
858                                 break;
859                         }
860                         if (!to) {
861                                 res = 0;
862                                 break;
863                         }
864                         f = ast_read(p->chan);
865                         if (!f) {
866                                 res = -1;
867                                 break;
868                         }
869                         if (f->frametype == AST_FRAME_DTMF)
870                                 res = f->subclass;
871                         else
872                                 res = 0;
873                         ast_frfree(f);
874                         ast_mutex_lock(&p->lock);
875                         if (!p->app_sleep_cond) {
876                                 ast_mutex_unlock(&p->lock);
877                                 res = 0;
878                                 break;
879                         } else if (res == '#') {
880                                 ast_mutex_unlock(&p->lock);
881                                 res = 1;
882                                 break;
883                         }
884                         ast_mutex_unlock(&p->lock);
885                         res = 0;
886                 }
887         } else
888                 res = -1;
889         return res;
890 }
891
892 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
893 {
894         struct agent_pvt *p;
895         struct ast_channel *ret=NULL;
896         
897
898         p = bridge->tech_pvt;
899         if (chan == p->chan)
900                 ret = bridge->_bridge;
901         else if (chan == bridge->_bridge)
902                 ret = p->chan;
903         if (option_debug)
904                 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
905         return ret;
906 }
907
908 /*--- agent_new: Create new agent channel ---*/
909 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
910 {
911         struct ast_channel *tmp;
912         struct ast_frame null_frame = { AST_FRAME_NULL };
913 #if 0
914         if (!p->chan) {
915                 ast_log(LOG_WARNING, "No channel? :(\n");
916                 return NULL;
917         }
918 #endif  
919         tmp = ast_channel_alloc(0);
920         if (tmp) {
921                 tmp->tech = &agent_tech;
922                 if (p->chan) {
923                         tmp->nativeformats = p->chan->nativeformats;
924                         tmp->writeformat = p->chan->writeformat;
925                         tmp->rawwriteformat = p->chan->writeformat;
926                         tmp->readformat = p->chan->readformat;
927                         tmp->rawreadformat = p->chan->readformat;
928                         ast_copy_string(tmp->language, p->chan->language, sizeof(tmp->language));
929                         ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
930                         ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
931                 } else {
932                         tmp->nativeformats = AST_FORMAT_SLINEAR;
933                         tmp->writeformat = AST_FORMAT_SLINEAR;
934                         tmp->rawwriteformat = AST_FORMAT_SLINEAR;
935                         tmp->readformat = AST_FORMAT_SLINEAR;
936                         tmp->rawreadformat = AST_FORMAT_SLINEAR;
937                 }
938                 if (p->pending)
939                         snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
940                 else
941                         snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
942                 tmp->type = channeltype;
943                 /* Safe, agentlock already held */
944                 ast_setstate(tmp, state);
945                 tmp->tech_pvt = p;
946                 p->owner = tmp;
947                 ast_mutex_lock(&usecnt_lock);
948                 usecnt++;
949                 ast_mutex_unlock(&usecnt_lock);
950                 ast_update_use_count();
951                 tmp->priority = 1;
952                 /* Wake up and wait for other applications (by definition the login app)
953                  * to release this channel). Takes ownership of the agent channel
954                  * to this thread only.
955                  * For signalling the other thread, ast_queue_frame is used until we
956                  * can safely use signals for this purpose. The pselect() needs to be
957                  * implemented in the kernel for this.
958                  */
959                 p->app_sleep_cond = 0;
960                 if( ast_mutex_trylock(&p->app_lock) )
961                 {
962                         if (p->chan) {
963                                 ast_queue_frame(p->chan, &null_frame);
964                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
965                                 ast_mutex_lock(&p->app_lock);
966                                 ast_mutex_lock(&p->lock);
967                         }
968                         if( !p->chan )
969                         {
970                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
971                                 p->owner = NULL;
972                                 tmp->tech_pvt = NULL;
973                                 p->app_sleep_cond = 1;
974                                 ast_channel_free( tmp );
975                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
976                                 ast_mutex_unlock(&p->app_lock);
977                                 return NULL;
978                         }
979                 }
980                 p->owning_app = pthread_self();
981                 /* After the above step, there should not be any blockers. */
982                 if (p->chan) {
983                         if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
984                                 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
985                                 CRASH;
986                         }
987                         ast_moh_stop(p->chan);
988                 }
989         } else
990                 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
991         return tmp;
992 }
993
994
995 /**
996  * Read configuration data. The file named agents.conf.
997  *
998  * @returns Always 0, or so it seems.
999  */
1000 static int read_agent_config(void)
1001 {
1002         struct ast_config *cfg;
1003         struct ast_variable *v;
1004         struct agent_pvt *p, *pl, *pn;
1005         char *general_val;
1006
1007         group = 0;
1008         autologoff = 0;
1009         wrapuptime = 0;
1010         ackcall = 0;
1011         cfg = ast_config_load(config);
1012         if (!cfg) {
1013                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1014                 return 0;
1015         }
1016         ast_mutex_lock(&agentlock);
1017         p = agents;
1018         while(p) {
1019                 p->dead = 1;
1020                 p = p->next;
1021         }
1022         strcpy(moh, "default");
1023         /* set the default recording values */
1024         recordagentcalls = 0;
1025         createlink = 0;
1026         strcpy(recordformat, "wav");
1027         strcpy(recordformatext, "wav");
1028         urlprefix[0] = '\0';
1029         savecallsin[0] = '\0';
1030
1031         /* Read in [general] section for persistance */
1032         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1033                 persistent_agents = ast_true(general_val);
1034
1035         /* Read in the [agents] section */
1036         v = ast_variable_browse(cfg, "agents");
1037         while(v) {
1038                 /* Create the interface list */
1039                 if (!strcasecmp(v->name, "agent")) {
1040                         add_agent(v->value, 0);
1041                 } else if (!strcasecmp(v->name, "group")) {
1042                         group = ast_get_group(v->value);
1043                 } else if (!strcasecmp(v->name, "autologoff")) {
1044                         autologoff = atoi(v->value);
1045                         if (autologoff < 0)
1046                                 autologoff = 0;
1047                 } else if (!strcasecmp(v->name, "ackcall")) {
1048                         if (!strcasecmp(v->value, "always"))
1049                                 ackcall = 2;
1050                         else if (ast_true(v->value))
1051                                 ackcall = 1;
1052                         else
1053                                 ackcall = 0;
1054                 } else if (!strcasecmp(v->name, "wrapuptime")) {
1055                         wrapuptime = atoi(v->value);
1056                         if (wrapuptime < 0)
1057                                 wrapuptime = 0;
1058                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1059                         maxlogintries = atoi(v->value);
1060                         if (maxlogintries < 0)
1061                                 maxlogintries = 0;
1062                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1063                         strcpy(agentgoodbye,v->value);
1064                 } else if (!strcasecmp(v->name, "musiconhold")) {
1065                         ast_copy_string(moh, v->value, sizeof(moh));
1066                 } else if (!strcasecmp(v->name, "updatecdr")) {
1067                         if (ast_true(v->value))
1068                                 updatecdr = 1;
1069                         else
1070                                 updatecdr = 0;
1071                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1072                         recordagentcalls = ast_true(v->value);
1073                 } else if (!strcasecmp(v->name, "createlink")) {
1074                         createlink = ast_true(v->value);
1075                 } else if (!strcasecmp(v->name, "recordformat")) {
1076                         ast_copy_string(recordformat, v->value, sizeof(recordformat));
1077                         if (!strcasecmp(v->value, "wav49"))
1078                                 strcpy(recordformatext, "WAV");
1079                         else
1080                                 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1081                 } else if (!strcasecmp(v->name, "urlprefix")) {
1082                         ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1083                         if (urlprefix[strlen(urlprefix) - 1] != '/')
1084                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1085                 } else if (!strcasecmp(v->name, "savecallsin")) {
1086                         if (v->value[0] == '/')
1087                                 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1088                         else
1089                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1090                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1091                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1092                 } else if (!strcasecmp(v->name, "custom_beep")) {
1093                         ast_copy_string(beep, v->value, sizeof(beep));
1094                 }
1095                 v = v->next;
1096         }
1097         p = agents;
1098         pl = NULL;
1099         while(p) {
1100                 pn = p->next;
1101                 if (p->dead) {
1102                         /* Unlink */
1103                         if (pl)
1104                                 pl->next = p->next;
1105                         else
1106                                 agents = p->next;
1107                         /* Destroy if  appropriate */
1108                         if (!p->owner) {
1109                                 if (!p->chan) {
1110                                         ast_mutex_destroy(&p->lock);
1111                                         ast_mutex_destroy(&p->app_lock);
1112                                         free(p);
1113                                 } else {
1114                                         /* Cause them to hang up */
1115                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1116                                 }
1117                         }
1118                 } else
1119                         pl = p;
1120                 p = pn;
1121         }
1122         ast_mutex_unlock(&agentlock);
1123         ast_config_destroy(cfg);
1124         return 0;
1125 }
1126
1127 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1128 {
1129         struct ast_channel *chan=NULL, *parent=NULL;
1130         struct agent_pvt *p;
1131         int res;
1132
1133         if (option_debug)
1134                 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1135         if (needlock)
1136                 ast_mutex_lock(&agentlock);
1137         p = agents;
1138         while(p) {
1139                 if (p == newlyavailable) {
1140                         p = p->next;
1141                         continue;
1142                 }
1143                 ast_mutex_lock(&p->lock);
1144                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1145                         if (option_debug)
1146                                 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1147                         /* We found a pending call, time to merge */
1148                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
1149                         parent = p->owner;
1150                         p->abouttograb = 1;
1151                         ast_mutex_unlock(&p->lock);
1152                         break;
1153                 }
1154                 ast_mutex_unlock(&p->lock);
1155                 p = p->next;
1156         }
1157         if (needlock)
1158                 ast_mutex_unlock(&agentlock);
1159         if (parent && chan)  {
1160                 if (newlyavailable->ackcall > 1) {
1161                         /* Don't do beep here */
1162                         res = 0;
1163                 } else {
1164                         if (option_debug > 2)
1165                                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1166                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1167                         if (option_debug > 2)
1168                                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1169                         if (!res) {
1170                                 res = ast_waitstream(newlyavailable->chan, "");
1171                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1172                         }
1173                 }
1174                 if (!res) {
1175                         /* Note -- parent may have disappeared */
1176                         if (p->abouttograb) {
1177                                 newlyavailable->acknowledged = 1;
1178                                 /* Safe -- agent lock already held */
1179                                 ast_setstate(parent, AST_STATE_UP);
1180                                 ast_setstate(chan, AST_STATE_UP);
1181                                 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1182                                 /* Go ahead and mark the channel as a zombie so that masquerade will
1183                                    destroy it for us, and we need not call ast_hangup */
1184                                 ast_mutex_lock(&parent->lock);
1185                                 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1186                                 ast_channel_masquerade(parent, chan);
1187                                 ast_mutex_unlock(&parent->lock);
1188                                 p->abouttograb = 0;
1189                         } else {
1190                                 if (option_debug)
1191                                         ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1192                                 agent_cleanup(newlyavailable);
1193                         }
1194                 } else {
1195                         if (option_debug)
1196                                 ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
1197                         agent_cleanup(newlyavailable);
1198                 }
1199         }
1200         return 0;
1201 }
1202
1203 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1204 {
1205         struct agent_pvt *p;
1206         int res=0;
1207
1208         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1209         if (needlock)
1210                 ast_mutex_lock(&agentlock);
1211         p = agents;
1212         while(p) {
1213                 if (p == newlyavailable) {
1214                         p = p->next;
1215                         continue;
1216                 }
1217                 ast_mutex_lock(&p->lock);
1218                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1219                         if (option_debug)
1220                                 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1221                         ast_mutex_unlock(&p->lock);
1222                         break;
1223                 }
1224                 ast_mutex_unlock(&p->lock);
1225                 p = p->next;
1226         }
1227         if (needlock)
1228                 ast_mutex_unlock(&agentlock);
1229         if (p) {
1230                 ast_mutex_unlock(&newlyavailable->lock);
1231                 if (option_debug > 2)
1232                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1233                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1234                 if (option_debug > 2)
1235                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1236                 if (!res) {
1237                         res = ast_waitstream(newlyavailable->chan, "");
1238                         if (option_debug)
1239                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1240                 }
1241                 ast_mutex_lock(&newlyavailable->lock);
1242         }
1243         return res;
1244 }
1245
1246 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1247 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1248 {
1249         struct agent_pvt *p;
1250         struct ast_channel *chan = NULL;
1251         char *s;
1252         ast_group_t groupmatch;
1253         int groupoff;
1254         int waitforagent=0;
1255         int hasagent = 0;
1256         struct timeval tv;
1257
1258         s = data;
1259         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1260                 groupmatch = (1 << groupoff);
1261         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1262                 groupmatch = (1 << groupoff);
1263                 waitforagent = 1;
1264         } else {
1265                 groupmatch = 0;
1266         }
1267
1268         /* Check actual logged in agents first */
1269         ast_mutex_lock(&agentlock);
1270         p = agents;
1271         while(p) {
1272                 ast_mutex_lock(&p->lock);
1273                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1274                                 ast_strlen_zero(p->loginchan)) {
1275                         if (p->chan)
1276                                 hasagent++;
1277                         if (!p->lastdisc.tv_sec) {
1278                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1279                                 if (!p->owner && p->chan) {
1280                                         /* Fixed agent */
1281                                         chan = agent_new(p, AST_STATE_DOWN);
1282                                 }
1283                                 if (chan) {
1284                                         ast_mutex_unlock(&p->lock);
1285                                         break;
1286                                 }
1287                         }
1288                 }
1289                 ast_mutex_unlock(&p->lock);
1290                 p = p->next;
1291         }
1292         if (!p) {
1293                 p = agents;
1294                 while(p) {
1295                         ast_mutex_lock(&p->lock);
1296                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1297                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1298                                         hasagent++;
1299                                 tv = ast_tvnow();
1300 #if 0
1301                                 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1302 #endif
1303                                 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1304                                         p->lastdisc = ast_tv(0, 0);
1305                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1306                                         if (!p->owner && p->chan) {
1307                                                 /* Could still get a fixed agent */
1308                                                 chan = agent_new(p, AST_STATE_DOWN);
1309                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1310                                                 /* Adjustable agent */
1311                                                 p->chan = ast_request("Local", format, p->loginchan, cause);
1312                                                 if (p->chan)
1313                                                         chan = agent_new(p, AST_STATE_DOWN);
1314                                         }
1315                                         if (chan) {
1316                                                 ast_mutex_unlock(&p->lock);
1317                                                 break;
1318                                         }
1319                                 }
1320                         }
1321                         ast_mutex_unlock(&p->lock);
1322                         p = p->next;
1323                 }
1324         }
1325
1326         if (!chan && waitforagent) {
1327                 /* No agent available -- but we're requesting to wait for one.
1328                    Allocate a place holder */
1329                 if (hasagent) {
1330                         if (option_debug)
1331                                 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1332                         p = add_agent(data, 1);
1333                         p->group = groupmatch;
1334                         chan = agent_new(p, AST_STATE_DOWN);
1335                         if (!chan) {
1336                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1337                         }
1338                 } else
1339                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1340         }
1341         if (hasagent)
1342                 *cause = AST_CAUSE_BUSY;
1343         else
1344                 *cause = AST_CAUSE_UNREGISTERED;
1345         ast_mutex_unlock(&agentlock);
1346         return chan;
1347 }
1348
1349 static int powerof(unsigned int v)
1350 {
1351         int x;
1352         for (x=0;x<32;x++) {
1353                 if (v & (1 << x)) return x;
1354         }
1355         return 0;
1356 }
1357
1358 /*--- action_agents: Manager routine for listing channels */
1359 static int action_agents(struct mansession *s, struct message *m)
1360 {
1361         char *id = astman_get_header(m,"ActionID");
1362         char idText[256] = "";
1363         struct agent_pvt *p;
1364         char *username = NULL;
1365         char *loginChan = NULL;
1366         char *talkingtoChan = NULL;
1367         char *status = NULL;
1368
1369         if (id && !ast_strlen_zero(id))
1370                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1371         astman_send_ack(s, m, "Agents will follow");
1372         ast_mutex_lock(&agentlock);
1373         p = agents;
1374         ast_mutex_lock(&s->lock);
1375         while(p) {
1376                 ast_mutex_lock(&p->lock);
1377
1378                 /* Status Values:
1379                         AGENT_LOGGEDOFF - Agent isn't logged in
1380                         AGENT_IDLE      - Agent is logged in, and waiting for call
1381                         AGENT_ONCALL    - Agent is logged in, and on a call
1382                         AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1383
1384                 if(!ast_strlen_zero(p->name)) {
1385                         username = p->name;
1386                 } else {
1387                         username = "None";
1388                 }
1389
1390                 /* Set a default status. It 'should' get changed. */
1391                 status = "AGENT_UNKNOWN";
1392
1393                 if(p->chan) {
1394                         loginChan = p->loginchan;
1395                         if(p->owner && p->owner->_bridge) {
1396                                 talkingtoChan = p->chan->cid.cid_num;
1397                                 status = "AGENT_ONCALL";
1398                         } else {
1399                                 talkingtoChan = "n/a";
1400                                 status = "AGENT_IDLE";
1401                         }
1402                 } else if(!ast_strlen_zero(p->loginchan)) {
1403                         loginChan = p->loginchan;
1404                         talkingtoChan = "n/a";
1405                         status = "AGENT_IDLE";
1406                         if(p->acknowledged) {
1407                                 sprintf(loginChan, " %s (Confirmed)", loginChan);
1408                         }
1409                 } else {
1410                         loginChan = "n/a";
1411                         talkingtoChan = "n/a";
1412                         status = "AGENT_LOGGEDOFF";
1413                 }
1414
1415                 ast_cli(s->fd, "Event: Agents\r\n"
1416                                 "Agent: %s\r\n"
1417                                 "Name: %s\r\n"
1418                                 "Status: %s\r\n"
1419                                 "LoggedInChan: %s\r\n"
1420                                 "LoggedInTime: %ld\r\n"
1421                                 "TalkingTo: %s\r\n"
1422                                 "%s"
1423                                 "\r\n",
1424                                 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan,idText);
1425                 ast_mutex_unlock(&p->lock);
1426                 p = p->next;
1427         }
1428         ast_mutex_unlock(&agentlock);
1429         ast_cli(s->fd, "Event: AgentsComplete\r\n"
1430                         "%s"
1431                         "\r\n",idText);
1432         ast_mutex_unlock(&s->lock);
1433
1434         return 0;
1435 }
1436
1437 static int agent_logoff(char *agent, int soft)
1438 {
1439         struct agent_pvt *p;
1440         long logintime;
1441         int ret = -1; /* Return -1 if no agent if found */
1442
1443         for (p=agents; p; p=p->next) {
1444                 if (!strcasecmp(p->agent, agent)) {
1445                         if (!soft) {
1446                                 if (p->owner) {
1447                                         ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1448                                 }
1449                                 if (p->chan) {
1450                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1451                                 }
1452                         }
1453                         ret = 0; /* found an agent => return 0 */
1454                         logintime = time(NULL) - p->loginstart;
1455                         p->loginstart = 0;
1456                         
1457                         manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1458                                 "Agent: %s\r\n"
1459                                 "Loginchan: %s\r\n"
1460                                 "Logintime: %ld\r\n",
1461                                 p->agent, p->loginchan, logintime);
1462                         ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1463                         p->loginchan[0] = '\0';
1464                         set_agentbycallerid(p);
1465                         p->logincallerid[0] = '\0';
1466                         ast_device_state_changed("Agent/%s", p->agent);
1467                         if (persistent_agents)
1468                                 dump_agents();
1469                         break;
1470                 }
1471         }
1472
1473         return ret;
1474 }
1475
1476 static int agent_logoff_cmd(int fd, int argc, char **argv)
1477 {
1478         int ret;
1479         char *agent;
1480
1481         if (argc < 3 || argc > 4)
1482                 return RESULT_SHOWUSAGE;
1483         if (argc == 4 && strcasecmp(argv[3], "soft"))
1484                 return RESULT_SHOWUSAGE;
1485
1486         agent = argv[2] + 6;
1487         ret = agent_logoff(agent, argc == 4);
1488         if (ret == 0)
1489                 ast_cli(fd, "Logging out %s\n", agent);
1490
1491         return RESULT_SUCCESS;
1492 }
1493
1494 static int action_agent_logoff(struct mansession *s, struct message *m)
1495 {
1496         char *agent = astman_get_header(m, "Agent");
1497         char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1498         int soft;
1499         int ret; /* return value of agent_logoff */
1500
1501         if (!agent || ast_strlen_zero(agent)) {
1502                 astman_send_error(s, m, "No agent specified");
1503                 return 0;
1504         }
1505
1506         if (ast_true(soft_s))
1507                 soft = 1;
1508         else
1509                 soft = 0;
1510
1511         ret = agent_logoff(agent, soft);
1512         if (ret == 0)
1513                 astman_send_ack(s, m, "Agent logged out");
1514         else
1515                 astman_send_error(s, m, "No such agent");
1516
1517         return 0;
1518 }
1519
1520 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1521 {
1522         struct agent_pvt *p;
1523         char name[AST_MAX_AGENT];
1524         int which = 0;
1525
1526         if (pos == 2) {
1527                 for (p=agents; p; p=p->next) {
1528                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1529                         if (!strncasecmp(word, name, strlen(word))) {
1530                                 if (++which > state) {
1531                                         return strdup(name);
1532                                 }
1533                         }
1534                 }
1535         } else if (pos == 3 && state == 0) {
1536                 return strdup("soft");
1537         }
1538         return NULL;
1539 }
1540
1541 /**
1542  * Show agents in cli.
1543  */
1544 static int agents_show(int fd, int argc, char **argv)
1545 {
1546         struct agent_pvt *p;
1547         char username[AST_MAX_BUF];
1548         char location[AST_MAX_BUF] = "";
1549         char talkingto[AST_MAX_BUF] = "";
1550         char moh[AST_MAX_BUF];
1551         int count_agents = 0;           /* Number of agents configured */
1552         int online_agents = 0;          /* Number of online agents */
1553         int offline_agents = 0;         /* Number of offline agents */
1554         if (argc != 2)
1555                 return RESULT_SHOWUSAGE;
1556         ast_mutex_lock(&agentlock);
1557         p = agents;
1558         while(p) {
1559                 ast_mutex_lock(&p->lock);
1560                 if (p->pending) {
1561                         if (p->group)
1562                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1563                         else
1564                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1565                 } else {
1566                         if (!ast_strlen_zero(p->name))
1567                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1568                         else
1569                                 username[0] = '\0';
1570                         if (p->chan) {
1571                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1572                                 if (p->owner && ast_bridged_channel(p->owner)) {
1573                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1574                                 } else {
1575                                         strcpy(talkingto, " is idle");
1576                                 }
1577                                 online_agents++;
1578                         } else if (!ast_strlen_zero(p->loginchan)) {
1579                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1580                                 talkingto[0] = '\0';
1581                                 online_agents++;
1582                                 if (p->acknowledged)
1583                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1584                         } else {
1585                                 strcpy(location, "not logged in");
1586                                 talkingto[0] = '\0';
1587                                 offline_agents++;
1588                         }
1589                         if (!ast_strlen_zero(p->moh))
1590                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1591                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1592                                         username, location, talkingto, moh);
1593                         count_agents++;
1594                 }
1595                 ast_mutex_unlock(&p->lock);
1596                 p = p->next;
1597         }
1598         ast_mutex_unlock(&agentlock);
1599         if ( !count_agents ) {
1600                 ast_cli(fd, "No Agents are configured in %s\n",config);
1601         } else {
1602                 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1603         }
1604         ast_cli(fd, "\n");
1605                         
1606         return RESULT_SUCCESS;
1607 }
1608
1609 static char show_agents_usage[] = 
1610 "Usage: show agents\n"
1611 "       Provides summary information on agents.\n";
1612
1613 static char agent_logoff_usage[] =
1614 "Usage: agent logoff <channel> [soft]\n"
1615 "       Sets an agent as no longer logged in.\n"
1616 "       If 'soft' is specified, do not hangup existing calls.\n";
1617
1618 static struct ast_cli_entry cli_show_agents = {
1619         { "show", "agents", NULL }, agents_show, 
1620         "Show status of agents", show_agents_usage, NULL };
1621
1622 static struct ast_cli_entry cli_agent_logoff = {
1623         { "agent", "logoff", NULL }, agent_logoff_cmd, 
1624         "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1625
1626 STANDARD_LOCAL_USER;
1627 LOCAL_USER_DECL;
1628
1629 /*--- __login_exec: Log in agent application ---*/
1630 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1631 {
1632         int res=0;
1633         int tries = 0;
1634         int max_login_tries = maxlogintries;
1635         struct agent_pvt *p;
1636         struct localuser *u;
1637         int login_state = 0;
1638         char user[AST_MAX_AGENT] = "";
1639         char pass[AST_MAX_AGENT];
1640         char agent[AST_MAX_AGENT] = "";
1641         char xpass[AST_MAX_AGENT] = "";
1642         char *errmsg;
1643         char info[512];
1644         char *opt_user = NULL;
1645         char *options = NULL;
1646         char option;
1647         char badoption[2];
1648         char *tmpoptions = NULL;
1649         char *context = NULL;
1650         char *exten = NULL;
1651         int play_announcement = 1;
1652         char agent_goodbye[AST_MAX_FILENAME_LEN];
1653         int update_cdr = updatecdr;
1654         char *filename = "agent-loginok";
1655         
1656         strcpy(agent_goodbye, agentgoodbye);
1657         LOCAL_USER_ADD(u);
1658
1659         /* Parse the arguments XXX Check for failure XXX */
1660         ast_copy_string(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION);
1661         opt_user = info;
1662         /* Set Channel Specific Login Overrides */
1663         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1664                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1665                 if (max_login_tries < 0)
1666                         max_login_tries = 0;
1667                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1668                 if (option_verbose > 2)
1669                         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);
1670         }
1671         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1672                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1673                         update_cdr = 1;
1674                 else
1675                         update_cdr = 0;
1676                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1677                 if (option_verbose > 2)
1678                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1679         }
1680         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1681                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1682                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1683                 if (option_verbose > 2)
1684                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1685         }
1686         /* End Channel Specific Login Overrides */
1687         /* Read command line options */
1688          if( opt_user ) {
1689                 options = strchr(opt_user, '|');
1690                 if (options) {
1691                         *options = '\0';
1692                         options++;
1693                         if (callbackmode) {
1694                                 context = strchr(options, '@');
1695                                 if (context) {
1696                                         *context = '\0';
1697                                         context++;
1698                                 }
1699                                 exten = options;
1700                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1701                                 if (!*exten)
1702                                         exten = NULL;
1703                         }
1704                 }
1705                 if (options) {
1706                         while (*options) {
1707                                 option = (char)options[0];
1708                                 if ((option >= 0) && (option <= '9'))
1709                                 {
1710                                         options++;
1711                                         continue;
1712                                 }
1713                                 if (option=='s')
1714                                         play_announcement = 0;
1715                                 else {
1716                                         badoption[0] = option;
1717                                         badoption[1] = '\0';
1718                                         tmpoptions=badoption;
1719                                         if (option_verbose > 2)
1720                                                 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1721                                 }
1722                                 options++;
1723                         }
1724                 }
1725         }
1726         /* End command line options */
1727
1728         if (chan->_state != AST_STATE_UP)
1729                 res = ast_answer(chan);
1730         if (!res) {
1731                 if( opt_user && !ast_strlen_zero(opt_user))
1732                         ast_copy_string(user, opt_user, AST_MAX_AGENT);
1733                 else
1734                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1735         }
1736         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1737                 tries++;
1738                 /* Check for password */
1739                 ast_mutex_lock(&agentlock);
1740                 p = agents;
1741                 while(p) {
1742                         if (!strcmp(p->agent, user) && !p->pending)
1743                                 ast_copy_string(xpass, p->password, sizeof(xpass));
1744                         p = p->next;
1745                 }
1746                 ast_mutex_unlock(&agentlock);
1747                 if (!res) {
1748                         if (!ast_strlen_zero(xpass))
1749                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1750                         else
1751                                 pass[0] = '\0';
1752                 }
1753                 errmsg = "agent-incorrect";
1754
1755 #if 0
1756                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1757 #endif          
1758
1759                 /* Check again for accuracy */
1760                 ast_mutex_lock(&agentlock);
1761                 p = agents;
1762                 while(p) {
1763                         ast_mutex_lock(&p->lock);
1764                         if (!strcmp(p->agent, user) &&
1765                                 !strcmp(p->password, pass) && !p->pending) {
1766                                         login_state = 1; /* Successful Login */
1767                                         /* Set Channel Specific Agent Overides */
1768                                         if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1769                                                 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1770                                                         p->ackcall = 2;
1771                                                 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1772                                                         p->ackcall = 1;
1773                                                 else
1774                                                         p->ackcall = 0;
1775                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1776                                                 if (option_verbose > 2)
1777                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1778                                         }
1779                                         if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1780                                                 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1781                                                 if (p->autologoff < 0)
1782                                                         p->autologoff = 0;
1783                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1784                                                 if (option_verbose > 2)
1785                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1786                                         }
1787                                         if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1788                                                 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1789                                                 if (p->wrapuptime < 0)
1790                                                         p->wrapuptime = 0;
1791                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1792                                                 if (option_verbose > 2)
1793                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1794                                         }
1795                                         /* End Channel Specific Agent Overides */
1796                                         if (!p->chan) {
1797                                                 char last_loginchan[80] = "";
1798                                                 long logintime;
1799                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1800
1801                                                 if (callbackmode) {
1802                                                         char tmpchan[AST_MAX_BUF] = "";
1803                                                         int pos = 0;
1804                                                         /* Retrieve login chan */
1805                                                         for (;;) {
1806                                                                 if (exten) {
1807                                                                         ast_copy_string(tmpchan, exten, sizeof(tmpchan));
1808                                                                         res = 0;
1809                                                                 } else
1810                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1811                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1812                                                                                         1, NULL))
1813                                                                         break;
1814                                                                 if (exten) {
1815                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1816                                                                         exten = NULL;
1817                                                                         pos = 0;
1818                                                                 } else {
1819                                                                         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);
1820                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1821                                                                         if (!res)
1822                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1823                                                                         if (res > 0) {
1824                                                                                 tmpchan[0] = res;
1825                                                                                 tmpchan[1] = '\0';
1826                                                                                 pos = 1;
1827                                                                         } else {
1828                                                                                 tmpchan[0] = '\0';
1829                                                                                 pos = 0;
1830                                                                         }
1831                                                                 }
1832                                                         }
1833                                                         exten = tmpchan;
1834                                                         if (!res) {
1835                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1836                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1837                                                                 else {
1838                                                                         ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1839                                                                         ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1840                                                                 }
1841                                                                 p->acknowledged = 0;
1842                                                                 if (ast_strlen_zero(p->loginchan)) {
1843                                                                         login_state = 2;
1844                                                                         filename = "agent-loggedoff";
1845                                                                         set_agentbycallerid(p);
1846                                                                 } else {
1847                                                                         if (chan->cid.cid_num) {
1848                                                                                 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1849                                                                                 set_agentbycallerid(p);
1850                                                                         } else
1851                                                                                 p->logincallerid[0] = '\0';
1852                                                                 }
1853
1854                                                                 if(update_cdr && chan->cdr)
1855                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1856
1857                                                         }
1858                                                 } else {
1859                                                         p->loginchan[0] = '\0';
1860                                                         p->logincallerid[0] = '\0';
1861                                                         p->acknowledged = 0;
1862                                                 }
1863                                                 ast_mutex_unlock(&p->lock);
1864                                                 ast_mutex_unlock(&agentlock);
1865                                                 if( !res && play_announcement==1 )
1866                                                         res = ast_streamfile(chan, filename, chan->language);
1867                                                 if (!res)
1868                                                         ast_waitstream(chan, "");
1869                                                 ast_mutex_lock(&agentlock);
1870                                                 ast_mutex_lock(&p->lock);
1871                                                 if (!res) {
1872                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1873                                                         if (res)
1874                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1875                                                 }
1876                                                 if (!res) {
1877                                                         res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1878                                                         if (res)
1879                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1880                                                 }
1881                                                 /* Check once more just in case */
1882                                                 if (p->chan)
1883                                                         res = -1;
1884                                                 if (callbackmode && !res) {
1885                                                         /* Just say goodbye and be done with it */
1886                                                         if (!ast_strlen_zero(p->loginchan)) {
1887                                                                 if (p->loginstart == 0)
1888                                                                         time(&p->loginstart);
1889                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1890                                                                         "Agent: %s\r\n"
1891                                                                         "Loginchan: %s\r\n"
1892                                                                         "Uniqueid: %s\r\n",
1893                                                                         p->agent, p->loginchan, chan->uniqueid);
1894                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1895                                                                 if (option_verbose > 1)
1896                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1897                                                                 ast_device_state_changed("Agent/%s", p->agent);
1898                                                         } else {
1899                                                                 logintime = time(NULL) - p->loginstart;
1900                                                                 p->loginstart = 0;
1901                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1902                                                                         "Agent: %s\r\n"
1903                                                                         "Loginchan: %s\r\n"
1904                                                                         "Logintime: %ld\r\n"
1905                                                                         "Uniqueid: %s\r\n",
1906                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1907                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1908                                                                 if (option_verbose > 1)
1909                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1910                                                                 ast_device_state_changed("Agent/%s", p->agent);
1911                                                         }
1912                                                         ast_mutex_unlock(&agentlock);
1913                                                         if (!res)
1914                                                                 res = ast_safe_sleep(chan, 500);
1915                                                         ast_mutex_unlock(&p->lock);
1916                                                         if (persistent_agents)
1917                                                                 dump_agents();
1918                                                 } else if (!res) {
1919 #ifdef HONOR_MUSIC_CLASS
1920                                                         /* check if the moh class was changed with setmusiconhold */
1921                                                         if (*(chan->musicclass))
1922                                                                 ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
1923 #endif                                                          
1924                                                         ast_moh_start(chan, p->moh);
1925                                                         if (p->loginstart == 0)
1926                                                                 time(&p->loginstart);
1927                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1928                                                                 "Agent: %s\r\n"
1929                                                                 "Channel: %s\r\n"
1930                                                                 "Uniqueid: %s\r\n",
1931                                                                 p->agent, chan->name, chan->uniqueid);
1932                                                         if (update_cdr && chan->cdr)
1933                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1934                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1935                                                         if (option_verbose > 1)
1936                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1937                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1938                                                         /* Login this channel and wait for it to
1939                                                            go away */
1940                                                         p->chan = chan;
1941                                                         if (p->ackcall > 1)
1942                                                                 check_beep(p, 0);
1943                                                         else
1944                                                                 check_availability(p, 0);
1945                                                         ast_mutex_unlock(&p->lock);
1946                                                         ast_mutex_unlock(&agentlock);
1947                                                         ast_device_state_changed("Agent/%s", p->agent);
1948                                                         while (res >= 0) {
1949                                                                 ast_mutex_lock(&p->lock);
1950                                                                 if (p->chan != chan)
1951                                                                         res = -1;
1952                                                                 ast_mutex_unlock(&p->lock);
1953                                                                 /* Yield here so other interested threads can kick in. */
1954                                                                 sched_yield();
1955                                                                 if (res)
1956                                                                         break;
1957
1958                                                                 ast_mutex_lock(&agentlock);
1959                                                                 ast_mutex_lock(&p->lock);
1960                                                                 if (p->lastdisc.tv_sec) {
1961                                                                         if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
1962                                                                                         if (option_debug)
1963                                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1964                                                                                 p->lastdisc = ast_tv(0, 0);
1965                                                                                 if (p->ackcall > 1)
1966                                                                                         check_beep(p, 0);
1967                                                                                 else
1968                                                                                         check_availability(p, 0);
1969                                                                         }
1970                                                                 }
1971                                                                 ast_mutex_unlock(&p->lock);
1972                                                                 ast_mutex_unlock(&agentlock);
1973                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1974                                                                 ast_mutex_lock( &p->app_lock );
1975                                                                 ast_mutex_lock(&p->lock);
1976                                                                 p->owning_app = pthread_self();
1977                                                                 ast_mutex_unlock(&p->lock);
1978                                                                 if (p->ackcall > 1) 
1979                                                                         res = agent_ack_sleep(p);
1980                                                                 else
1981                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1982                                                                                                         agent_cont_sleep, p );
1983                                                                 ast_mutex_unlock( &p->app_lock );
1984                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1985                                                                         ast_mutex_lock(&agentlock);
1986                                                                         ast_mutex_lock(&p->lock);
1987                                                                         check_availability(p, 0);
1988                                                                         ast_mutex_unlock(&p->lock);
1989                                                                         ast_mutex_unlock(&agentlock);
1990                                                                         res = 0;
1991                                                                 }
1992                                                                 sched_yield();
1993                                                         }
1994                                                         ast_mutex_lock(&p->lock);
1995                                                         if (res && p->owner) 
1996                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1997                                                         /* Log us off if appropriate */
1998                                                         if (p->chan == chan)
1999                                                                 p->chan = NULL;
2000                                                         p->acknowledged = 0;
2001                                                         logintime = time(NULL) - p->loginstart;
2002                                                         p->loginstart = 0;
2003                                                         ast_mutex_unlock(&p->lock);
2004                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2005                                                                 "Agent: %s\r\n"
2006                                                                 "Logintime: %ld\r\n"
2007                                                                 "Uniqueid: %s\r\n",
2008                                                                 p->agent, logintime, chan->uniqueid);
2009                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2010                                                         if (option_verbose > 1)
2011                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
2012                                                         /* If there is no owner, go ahead and kill it now */
2013                                                         ast_device_state_changed("Agent/%s", p->agent);
2014                                                         if (p->dead && !p->owner) {
2015                                                                 ast_mutex_destroy(&p->lock);
2016                                                                 ast_mutex_destroy(&p->app_lock);
2017                                                                 free(p);
2018                                                         }
2019                                                 }
2020                                                 else {
2021                                                         ast_mutex_unlock(&p->lock);
2022                                                         p = NULL;
2023                                                 }
2024                                                 res = -1;
2025                                         } else {
2026                                                 ast_mutex_unlock(&p->lock);
2027                                                 errmsg = "agent-alreadyon";
2028                                                 p = NULL;
2029                                         }
2030                                         break;
2031                         }
2032                         ast_mutex_unlock(&p->lock);
2033                         p = p->next;
2034                 }
2035                 if (!p)
2036                         ast_mutex_unlock(&agentlock);
2037
2038                 if (!res && (max_login_tries==0 || tries < max_login_tries))
2039                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2040         }
2041                 
2042         LOCAL_USER_REMOVE(u);
2043         if (!res)
2044                 res = ast_safe_sleep(chan, 500);
2045
2046         /* AgentLogin() exit */
2047         if (!callbackmode) {
2048                 return -1;
2049         }
2050         /* AgentCallbackLogin() exit*/
2051         else {
2052                 /* Set variables */
2053                 if (login_state > 0) {
2054                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
2055                         if (login_state==1) {
2056                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
2057                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
2058                         }
2059                         else {
2060                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
2061                         }
2062                 }
2063                 else {
2064                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
2065                 }
2066                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
2067                         return 0;
2068                 /* Do we need to play agent-goodbye now that we will be hanging up? */
2069                 if (play_announcement==1) {
2070                         if (!res)
2071                                 res = ast_safe_sleep(chan, 1000);
2072                         res = ast_streamfile(chan, agent_goodbye, chan->language);
2073                         if (!res)
2074                                 res = ast_waitstream(chan, "");
2075                         if (!res)
2076                                 res = ast_safe_sleep(chan, 1000);
2077                 }
2078         }
2079         /* We should never get here if next priority exists when in callbackmode */
2080         return -1;
2081 }
2082
2083 static int login_exec(struct ast_channel *chan, void *data)
2084 {
2085         return __login_exec(chan, data, 0);
2086 }
2087
2088 static int callback_exec(struct ast_channel *chan, void *data)
2089 {
2090         return __login_exec(chan, data, 1);
2091 }
2092
2093 static int action_agent_callback_login(struct mansession *s, struct message *m)
2094 {
2095         char *agent = astman_get_header(m, "Agent");
2096         char *exten = astman_get_header(m, "Exten");
2097         char *context = astman_get_header(m, "Context");
2098         char *wrapuptime_s = astman_get_header(m, "WrapupTime");
2099         char *ackcall_s = astman_get_header(m, "AckCall");
2100         struct agent_pvt *p;
2101         int login_state = 0;
2102
2103         if (ast_strlen_zero(agent)) {
2104                 astman_send_error(s, m, "No agent specified");
2105                 return 0;
2106         }
2107
2108         if (ast_strlen_zero(exten)) {
2109                 astman_send_error(s, m, "No extension specified");
2110                 return 0;
2111         }
2112
2113         ast_mutex_lock(&agentlock);
2114         p = agents;
2115         while(p) {
2116                 if (strcmp(p->agent, agent) || p->pending) {
2117                         p = p->next;
2118                         continue;
2119                 }
2120                 if (p->chan) {
2121                         login_state = 2; /* already logged in (and on the phone)*/
2122                         break;
2123                 }
2124                 ast_mutex_lock(&p->lock);
2125                 login_state = 1; /* Successful Login */
2126                 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
2127                 
2128                 if (ast_strlen_zero(context))
2129                         snprintf(p->loginchan, sizeof(p->loginchan), "%s", exten);
2130                 else
2131                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
2132
2133                 if (wrapuptime_s && !ast_strlen_zero(wrapuptime_s)) {
2134                         p->wrapuptime = atoi(wrapuptime_s);
2135                         if (p->wrapuptime < 0)
2136                                 p->wrapuptime = 0;
2137                 }
2138
2139                 if (ast_true(ackcall_s))
2140                         p->ackcall = 1;
2141                 else
2142                         p->ackcall = 0;
2143
2144                 if (p->loginstart == 0)
2145                         time(&p->loginstart);
2146                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
2147                         "Agent: %s\r\n"
2148                         "Loginchan: %s\r\n",
2149                         p->agent, p->loginchan);
2150                 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
2151                 if (option_verbose > 1)
2152                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
2153                 ast_device_state_changed("Agent/%s", p->agent);
2154                 ast_mutex_unlock(&p->lock);
2155                 p = p->next;
2156         }
2157         ast_mutex_unlock(&agentlock);
2158
2159         if (login_state == 1)
2160                 astman_send_ack(s, m, "Agent logged in");
2161         else if (login_state == 0)
2162                 astman_send_error(s, m, "No such agent");
2163         else if (login_state == 2)
2164                 astman_send_error(s, m, "Agent already logged in");
2165
2166         return 0;
2167 }
2168 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2169 {
2170         int exitifnoagentid = 0;
2171         int nowarnings = 0;
2172         int changeoutgoing = 0;
2173         int res = 0;
2174         char agent[AST_MAX_AGENT], *tmp;
2175
2176         if (data) {
2177                 if (strchr(data, 'd'))
2178                         exitifnoagentid = 1;
2179                 if (strchr(data, 'n'))
2180                         nowarnings = 1;
2181                 if (strchr(data, 'c'))
2182                         changeoutgoing = 1;
2183         }
2184         if (chan->cid.cid_num) {
2185                 char agentvar[AST_MAX_BUF];
2186                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2187                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2188                         struct agent_pvt *p = agents;
2189                         ast_copy_string(agent, tmp, sizeof(agent));
2190                         ast_mutex_lock(&agentlock);
2191                         while (p) {
2192                                 if (!strcasecmp(p->agent, tmp)) {
2193                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2194                                         __agent_start_monitoring(chan, p, 1);
2195                                         break;
2196                                 }
2197                                 p = p->next;
2198                         }
2199                         ast_mutex_unlock(&agentlock);
2200                         
2201                 } else {
2202                         res = -1;
2203                         if (!nowarnings)
2204                                 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);
2205                 }
2206         } else {
2207                 res = -1;
2208                 if (!nowarnings)
2209                         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");
2210         }
2211         /* check if there is n + 101 priority */
2212         if (res) {
2213                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2214                         chan->priority+=100;
2215                         if (option_verbose > 2)
2216                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2217                }
2218                 else if (exitifnoagentid)
2219                         return res;
2220         }
2221         return 0;
2222 }
2223
2224 /* Dump AgentCallbackLogin agents to the database for persistence
2225  */
2226
2227 static void dump_agents(void)
2228 {
2229         struct agent_pvt *cur_agent = NULL;
2230         char buf[256];
2231
2232         for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2233                 if (cur_agent->chan)
2234                         continue;
2235
2236                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2237                         snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2238                         if (ast_db_put(pa_family, cur_agent->agent, buf))
2239                                 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2240                         else if (option_debug)
2241                                 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2242                 } else {
2243                         /* Delete -  no agent or there is an error */
2244                         ast_db_del(pa_family, cur_agent->agent);
2245                 }
2246         }
2247 }
2248
2249 /**
2250  * Reload the persistent agents from astdb.
2251  */
2252 static void reload_agents(void)
2253 {
2254         char *agent_num;
2255         struct ast_db_entry *db_tree;
2256         struct ast_db_entry *entry;
2257         struct agent_pvt *cur_agent;
2258         char agent_data[256];
2259         char *parse;
2260         char *agent_chan;
2261         char *agent_callerid;
2262
2263         db_tree = ast_db_gettree(pa_family, NULL);
2264
2265         ast_mutex_lock(&agentlock);
2266         for (entry = db_tree; entry; entry = entry->next) {
2267                 agent_num = entry->key + strlen(pa_family) + 2;
2268                 cur_agent = agents;
2269                 while (cur_agent) {
2270                         ast_mutex_lock(&cur_agent->lock);
2271                         if (strcmp(agent_num, cur_agent->agent) == 0)
2272                                 break;
2273                         ast_mutex_unlock(&cur_agent->lock);
2274                         cur_agent = cur_agent->next;
2275                 }
2276                 if (!cur_agent) {
2277                         ast_db_del(pa_family, agent_num);
2278                         continue;
2279                 } else
2280                         ast_mutex_unlock(&cur_agent->lock);
2281                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2282                         if (option_debug)
2283                                 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2284                         parse = agent_data;
2285                         agent_chan = strsep(&parse, ";");
2286                         agent_callerid = strsep(&parse, ";");
2287                         ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2288                         if (agent_callerid) {
2289                                 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2290                                 set_agentbycallerid(cur_agent);
2291                         } else
2292                                 cur_agent->logincallerid[0] = '\0';
2293                         if (cur_agent->loginstart == 0)
2294                                 time(&cur_agent->loginstart);
2295                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2296                 }
2297         }
2298         ast_mutex_unlock(&agentlock);
2299         if (db_tree) {
2300                 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2301                 ast_db_freetree(db_tree);
2302         }
2303 }
2304
2305
2306 /*--- agent_devicestate: Part of PBX channel interface ---*/
2307 static int agent_devicestate(void *data)
2308 {
2309         struct agent_pvt *p;
2310         char *s;
2311         ast_group_t groupmatch;
2312         int groupoff;
2313         int waitforagent=0;
2314         int res = AST_DEVICE_INVALID;
2315         
2316         s = data;
2317         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2318                 groupmatch = (1 << groupoff);
2319         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2320                 groupmatch = (1 << groupoff);
2321                 waitforagent = 1;
2322         } else {
2323                 groupmatch = 0;
2324         }
2325
2326         /* Check actual logged in agents first */
2327         ast_mutex_lock(&agentlock);
2328         p = agents;
2329         while(p) {
2330                 ast_mutex_lock(&p->lock);
2331                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2332                         if (p->owner) {
2333                                 if (res != AST_DEVICE_INUSE)
2334                                         res = AST_DEVICE_BUSY;
2335                         } else {
2336                                 if (res == AST_DEVICE_BUSY)
2337                                         res = AST_DEVICE_INUSE;
2338                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2339                                         if (res == AST_DEVICE_INVALID)
2340                                                 res = AST_DEVICE_UNKNOWN;
2341                                 } else if (res == AST_DEVICE_INVALID)   
2342                                         res = AST_DEVICE_UNAVAILABLE;
2343                         }
2344                         if (!strcmp(data, p->agent)) {
2345                                 ast_mutex_unlock(&p->lock);
2346                                 break;
2347                         }
2348                 }
2349                 ast_mutex_unlock(&p->lock);
2350                 p = p->next;
2351         }
2352         ast_mutex_unlock(&agentlock);
2353         return res;
2354 }
2355
2356 /**
2357  * Initialize the Agents module.
2358  * This funcion is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
2359  *
2360  * @returns int Always 0.
2361  */
2362 int load_module()
2363 {
2364         /* Make sure we can register our agent channel type */
2365         if (ast_channel_register(&agent_tech)) {
2366                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2367                 return -1;
2368         }
2369         /* Dialplan applications */
2370         ast_register_application(app, login_exec, synopsis, descrip);
2371         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2372         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2373         /* Manager commands */
2374         ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2375         ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2376         ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
2377         /* CLI Application */
2378         ast_cli_register(&cli_show_agents);
2379         ast_cli_register(&cli_agent_logoff);
2380         /* Read in the config */
2381         read_agent_config();
2382         if (persistent_agents)
2383                 reload_agents();
2384         return 0;
2385 }
2386
2387 int reload()
2388 {
2389         read_agent_config();
2390         if (persistent_agents)
2391                 reload_agents();
2392         return 0;
2393 }
2394
2395 int unload_module()
2396 {
2397         struct agent_pvt *p;
2398         /* First, take us out of the channel loop */
2399         /* Unregister CLI application */
2400         ast_cli_unregister(&cli_show_agents);
2401         ast_cli_unregister(&cli_agent_logoff);
2402         /* Unregister dialplan applications */
2403         ast_unregister_application(app);
2404         ast_unregister_application(app2);
2405         ast_unregister_application(app3);
2406         /* Unregister manager command */
2407         ast_manager_unregister("Agents");
2408         ast_manager_unregister("AgentLogoff");
2409         ast_manager_unregister("AgentCallbackLogin");
2410         /* Unregister channel */
2411         ast_channel_unregister(&agent_tech);
2412         if (!ast_mutex_lock(&agentlock)) {
2413                 /* Hangup all interfaces if they have an owner */
2414                 p = agents;
2415                 while(p) {
2416                         if (p->owner)
2417                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2418                         p = p->next;
2419                 }
2420                 agents = NULL;
2421                 ast_mutex_unlock(&agentlock);
2422         } else {
2423                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2424                 return -1;
2425         }               
2426         return 0;
2427 }
2428
2429 int usecount()
2430 {
2431         return usecnt;
2432 }
2433
2434 char *key()
2435 {
2436         return ASTERISK_GPL_KEY;
2437 }
2438
2439 char *description()
2440 {
2441         return (char *) desc;
2442 }
2443