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