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