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