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