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