Merged revisions 80426 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 && !p->chan->generator)  \
195                         ast_set_read_format(p->chan, ast->rawreadformat); \
196                 if (p->chan->writeformat != ast->rawwriteformat && !p->chan->generator) \
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_channel_set_fd(ast, x, p->chan->fds[x]); \
211                 } \
212                 ast_channel_set_fd(ast, 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, 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, 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                                         ast_verb(3, "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
462                                         /* Don't pass answer along */
463                                         ast_frfree(f);
464                                         f = &ast_null_frame;
465                                 } else {
466                                         p->acknowledged = 1;
467                                         /* Use the builtin answer frame for the 
468                                            recording start check below. */
469                                         ast_frfree(f);
470                                         f = &answer_frame;
471                                 }
472                         }
473                         break;
474                 case AST_FRAME_DTMF_BEGIN:
475                 case AST_FRAME_DTMF_END:
476                         if (!p->acknowledged && (f->subclass == '#')) {
477                                 ast_verb(3, "%s acknowledged\n", p->chan->name);
478                                 p->acknowledged = 1;
479                                 ast_frfree(f);
480                                 f = &answer_frame;
481                         } else if (f->subclass == '*' && endcall) {
482                                 /* terminates call */
483                                 ast_frfree(f);
484                                 f = NULL;
485                         }
486                         break;
487                 case AST_FRAME_VOICE:
488                 case AST_FRAME_VIDEO:
489                         /* don't pass voice or video until the call is acknowledged */
490                         if (!p->acknowledged) {
491                                 ast_frfree(f);
492                                 f = &ast_null_frame;
493                         }
494                 default:
495                         /* pass everything else on through */
496                         break;
497                 }
498         }
499
500         CLEANUP(ast,p);
501         if (p->chan && !p->chan->_bridge) {
502                 if (strcasecmp(p->chan->tech->type, "Local")) {
503                         p->chan->_bridge = ast;
504                         if (p->chan)
505                                 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
506                 }
507         }
508         ast_mutex_unlock(&p->lock);
509         if (recordagentcalls && f == &answer_frame)
510                 agent_start_monitoring(ast,0);
511         return f;
512 }
513
514 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
515 {
516         struct agent_pvt *p = ast->tech_pvt;
517         int res = -1;
518         ast_mutex_lock(&p->lock);
519         if (p->chan) 
520                 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
521         ast_mutex_unlock(&p->lock);
522         return res;
523 }
524
525 static int agent_sendtext(struct ast_channel *ast, const char *text)
526 {
527         struct agent_pvt *p = ast->tech_pvt;
528         int res = -1;
529         ast_mutex_lock(&p->lock);
530         if (p->chan) 
531                 res = ast_sendtext(p->chan, text);
532         ast_mutex_unlock(&p->lock);
533         return res;
534 }
535
536 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
537 {
538         struct agent_pvt *p = ast->tech_pvt;
539         int res = -1;
540         CHECK_FORMATS(ast, p);
541         ast_mutex_lock(&p->lock);
542         if (!p->chan) 
543                 res = 0;
544         else {
545                 if ((f->frametype != AST_FRAME_VOICE) ||
546                     (f->frametype != AST_FRAME_VIDEO) ||
547                     (f->subclass == p->chan->writeformat)) {
548                         res = ast_write(p->chan, f);
549                 } else {
550                         ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n", 
551                                 f->frametype == AST_FRAME_VOICE ? "audio" : "video",
552                                 ast->name, p->chan->name);
553                         res = 0;
554                 }
555         }
556         CLEANUP(ast, p);
557         ast_mutex_unlock(&p->lock);
558         return res;
559 }
560
561 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
562 {
563         struct agent_pvt *p = newchan->tech_pvt;
564         ast_mutex_lock(&p->lock);
565         if (p->owner != oldchan) {
566                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
567                 ast_mutex_unlock(&p->lock);
568                 return -1;
569         }
570         p->owner = newchan;
571         ast_mutex_unlock(&p->lock);
572         return 0;
573 }
574
575 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
576 {
577         struct agent_pvt *p = ast->tech_pvt;
578         int res = -1;
579         ast_mutex_lock(&p->lock);
580         if (p->chan)
581                 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
582         else
583                 res = 0;
584         ast_mutex_unlock(&p->lock);
585         return res;
586 }
587
588 static int agent_digit_begin(struct ast_channel *ast, char digit)
589 {
590         struct agent_pvt *p = ast->tech_pvt;
591         ast_mutex_lock(&p->lock);
592         ast_senddigit_begin(p->chan, digit);
593         ast_mutex_unlock(&p->lock);
594         return 0;
595 }
596
597 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
598 {
599         struct agent_pvt *p = ast->tech_pvt;
600         ast_mutex_lock(&p->lock);
601         ast_senddigit_end(p->chan, digit, duration);
602         ast_mutex_unlock(&p->lock);
603         return 0;
604 }
605
606 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
607 {
608         struct agent_pvt *p = ast->tech_pvt;
609         int res = -1;
610         int newstate=0;
611         ast_mutex_lock(&p->lock);
612         p->acknowledged = 0;
613         if (!p->chan) {
614                 if (p->pending) {
615                         ast_debug(1, "Pretending to dial on pending agent\n");
616                         newstate = AST_STATE_DIALING;
617                         res = 0;
618                 } else {
619                         ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
620                         res = -1;
621                 }
622                 ast_mutex_unlock(&p->lock);
623                 if (newstate)
624                         ast_setstate(ast, newstate);
625                 return res;
626         } else if (!ast_strlen_zero(p->loginchan)) {
627                 time(&p->start);
628                 /* Call on this agent */
629                 ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
630                 ast_set_callerid(p->chan,
631                         ast->cid.cid_num, ast->cid.cid_name, NULL);
632                 ast_channel_inherit_variables(ast, p->chan);
633                 res = ast_call(p->chan, p->loginchan, 0);
634                 CLEANUP(ast,p);
635                 ast_mutex_unlock(&p->lock);
636                 return res;
637         }
638         ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
639         ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
640         res = ast_streamfile(p->chan, beep, p->chan->language);
641         ast_debug(3, "Played beep, result '%d'\n", res);
642         if (!res) {
643                 res = ast_waitstream(p->chan, "");
644                 ast_debug(3, "Waited for stream, result '%d'\n", res);
645         }
646         if (!res) {
647                 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
648                 ast_debug(3, "Set read format, result '%d'\n", res);
649                 if (res)
650                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
651         } else {
652                 /* Agent hung-up */
653                 p->chan = NULL;
654         }
655
656         if (!res) {
657                 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
658                 ast_debug(3, "Set write format, result '%d'\n", res);
659                 if (res)
660                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
661         }
662         if(!res) {
663                 /* Call is immediately up, or might need ack */
664                 if (p->ackcall > 1)
665                         newstate = AST_STATE_RINGING;
666                 else {
667                         newstate = AST_STATE_UP;
668                         if (recordagentcalls)
669                                 agent_start_monitoring(ast, 0);
670                         p->acknowledged = 1;
671                 }
672                 res = 0;
673         }
674         CLEANUP(ast, p);
675         ast_mutex_unlock(&p->lock);
676         if (newstate)
677                 ast_setstate(ast, newstate);
678         return res;
679 }
680
681 /*! \brief store/clear the global variable that stores agentid based on the callerid */
682 static void set_agentbycallerid(const char *callerid, const char *agent)
683 {
684         char buf[AST_MAX_BUF];
685
686         /* if there is no Caller ID, nothing to do */
687         if (ast_strlen_zero(callerid))
688                 return;
689
690         snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
691         pbx_builtin_setvar_helper(NULL, buf, agent);
692 }
693
694 static int agent_hangup(struct ast_channel *ast)
695 {
696         struct agent_pvt *p = ast->tech_pvt;
697         int howlong = 0;
698         const char *status;
699         ast_mutex_lock(&p->lock);
700         p->owner = NULL;
701         ast->tech_pvt = NULL;
702         p->app_sleep_cond = 1;
703         p->acknowledged = 0;
704
705         /* if they really are hung up then set start to 0 so the test
706          * later if we're called on an already downed channel
707          * doesn't cause an agent to be logged out like when
708          * agent_request() is followed immediately by agent_hangup()
709          * as in apps/app_chanisavail.c:chanavail_exec()
710          */
711
712         ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
713         if (p->start && (ast->_state != AST_STATE_UP)) {
714                 howlong = time(NULL) - p->start;
715                 p->start = 0;
716         } else if (ast->_state == AST_STATE_RESERVED) 
717                 howlong = 0;
718         else
719                 p->start = 0; 
720         if (p->chan) {
721                 p->chan->_bridge = NULL;
722                 /* If they're dead, go ahead and hang up on the agent now */
723                 if (!ast_strlen_zero(p->loginchan)) {
724                         /* Store last disconnect time */
725                         if (p->wrapuptime)
726                                 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
727                         else
728                                 p->lastdisc = ast_tv(0,0);
729                         if (p->chan) {
730                                 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
731                                 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
732                                         long logintime = time(NULL) - p->loginstart;
733                                         p->loginstart = 0;
734                                         ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
735                                         agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
736                                 }
737                                 /* Recognize the hangup and pass it along immediately */
738                                 ast_hangup(p->chan);
739                                 p->chan = NULL;
740                         }
741                         ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
742                         if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
743                                 long logintime = time(NULL) - p->loginstart;
744                                 p->loginstart = 0;
745                                 if (!p->deferlogoff)
746                                         ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
747                                 p->deferlogoff = 0;
748                                 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
749                                 if (persistent_agents)
750                                         dump_agents();
751                         }
752                 } else if (p->dead) {
753                         ast_channel_lock(p->chan);
754                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
755                         ast_channel_unlock(p->chan);
756                 } else if (p->loginstart) {
757                         ast_channel_lock(p->chan);
758                         ast_indicate_data(p->chan, AST_CONTROL_HOLD, 
759                                 S_OR(p->moh, NULL),
760                                 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
761                         ast_channel_unlock(p->chan);
762                 }
763         }
764         ast_mutex_unlock(&p->lock);
765
766         /* Only register a device state change if the agent is still logged in */
767         if (!p->loginstart) {
768                 p->loginchan[0] = '\0';
769                 p->logincallerid[0] = '\0';
770                 if (persistent_agents)
771                         dump_agents();
772         } else {
773                 ast_device_state_changed("Agent/%s", p->agent);
774         }
775
776         if (p->pending) {
777                 AST_LIST_LOCK(&agents);
778                 AST_LIST_REMOVE(&agents, p, list);
779                 AST_LIST_UNLOCK(&agents);
780         }
781         if (p->abouttograb) {
782                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
783                    kill it later */
784                 p->abouttograb = 0;
785         } else if (p->dead) {
786                 ast_mutex_destroy(&p->lock);
787                 ast_mutex_destroy(&p->app_lock);
788                 ast_free(p);
789         } else {
790                 if (p->chan) {
791                         /* Not dead -- check availability now */
792                         ast_mutex_lock(&p->lock);
793                         /* Store last disconnect time */
794                         p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
795                         ast_mutex_unlock(&p->lock);
796                 }
797                 /* Release ownership of the agent to other threads (presumably running the login app). */
798                 if (ast_strlen_zero(p->loginchan))
799                         ast_mutex_unlock(&p->app_lock);
800         }
801         return 0;
802 }
803
804 static int agent_cont_sleep( void *data )
805 {
806         struct agent_pvt *p;
807         int res;
808
809         p = (struct agent_pvt *)data;
810
811         ast_mutex_lock(&p->lock);
812         res = p->app_sleep_cond;
813         if (p->lastdisc.tv_sec) {
814                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) 
815                         res = 1;
816         }
817         ast_mutex_unlock(&p->lock);
818
819         if (!res)
820                 ast_debug(5, "agent_cont_sleep() returning %d\n", res );
821
822         return res;
823 }
824
825 static int agent_ack_sleep(void *data)
826 {
827         struct agent_pvt *p;
828         int res=0;
829         int to = 1000;
830         struct ast_frame *f;
831
832         /* Wait a second and look for something */
833
834         p = (struct agent_pvt *) data;
835         if (!p->chan) 
836                 return -1;
837
838         for(;;) {
839                 to = ast_waitfor(p->chan, to);
840                 if (to < 0) 
841                         return -1;
842                 if (!to) 
843                         return 0;
844                 f = ast_read(p->chan);
845                 if (!f) 
846                         return -1;
847                 if (f->frametype == AST_FRAME_DTMF)
848                         res = f->subclass;
849                 else
850                         res = 0;
851                 ast_frfree(f);
852                 ast_mutex_lock(&p->lock);
853                 if (!p->app_sleep_cond) {
854                         ast_mutex_unlock(&p->lock);
855                         return 0;
856                 } else if (res == '#') {
857                         ast_mutex_unlock(&p->lock);
858                         return 1;
859                 }
860                 ast_mutex_unlock(&p->lock);
861                 res = 0;
862         }
863         return res;
864 }
865
866 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
867 {
868         struct agent_pvt *p = bridge->tech_pvt;
869         struct ast_channel *ret = NULL;
870
871         if (p) {
872                 if (chan == p->chan)
873                         ret = bridge->_bridge;
874                 else if (chan == bridge->_bridge)
875                         ret = p->chan;
876         }
877
878         ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
879         return ret;
880 }
881
882 /*! \brief Create new agent channel */
883 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
884 {
885         struct ast_channel *tmp;
886 #if 0
887         if (!p->chan) {
888                 ast_log(LOG_WARNING, "No channel? :(\n");
889                 return NULL;
890         }
891 #endif  
892         if (p->pending)
893                 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);
894         else
895                 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
896         if (!tmp) {
897                 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
898                 return NULL;
899         }
900
901         tmp->tech = &agent_tech;
902         if (p->chan) {
903                 tmp->nativeformats = p->chan->nativeformats;
904                 tmp->writeformat = p->chan->writeformat;
905                 tmp->rawwriteformat = p->chan->writeformat;
906                 tmp->readformat = p->chan->readformat;
907                 tmp->rawreadformat = p->chan->readformat;
908                 ast_string_field_set(tmp, language, p->chan->language);
909                 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
910                 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
911                 /* XXX Is this really all we copy form the originating channel?? */
912         } else {
913                 tmp->nativeformats = AST_FORMAT_SLINEAR;
914                 tmp->writeformat = AST_FORMAT_SLINEAR;
915                 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
916                 tmp->readformat = AST_FORMAT_SLINEAR;
917                 tmp->rawreadformat = AST_FORMAT_SLINEAR;
918         }
919         /* Safe, agentlock already held */
920         tmp->tech_pvt = p;
921         p->owner = tmp;
922         tmp->priority = 1;
923         /* Wake up and wait for other applications (by definition the login app)
924          * to release this channel). Takes ownership of the agent channel
925          * to this thread only.
926          * For signalling the other thread, ast_queue_frame is used until we
927          * can safely use signals for this purpose. The pselect() needs to be
928          * implemented in the kernel for this.
929          */
930         p->app_sleep_cond = 0;
931         if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) {
932                 if (p->chan) {
933                         ast_queue_frame(p->chan, &ast_null_frame);
934                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
935                         ast_mutex_lock(&p->app_lock);
936                         ast_mutex_lock(&p->lock);
937                 } else {
938                         ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
939                         p->owner = NULL;
940                         tmp->tech_pvt = NULL;
941                         p->app_sleep_cond = 1;
942                         ast_channel_free( tmp );
943                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
944                         ast_mutex_unlock(&p->app_lock);
945                         return NULL;
946                 }
947         } else if (!ast_strlen_zero(p->loginchan)) {
948                 if (p->chan)
949                         ast_queue_frame(p->chan, &ast_null_frame);
950                 if (!p->chan) {
951                         ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
952                         p->owner = NULL;
953                         tmp->tech_pvt = NULL;
954                         p->app_sleep_cond = 1;
955                         ast_channel_free( tmp );
956                         ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
957                         return NULL;
958                 }       
959         } 
960         if (p->chan)
961                 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
962         p->owning_app = pthread_self();
963         /* After the above step, there should not be any blockers. */
964         if (p->chan) {
965                 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
966                         ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
967                         CRASH;
968                 }
969         }
970         return tmp;
971 }
972
973
974 /*!
975  * Read configuration data. The file named agents.conf.
976  *
977  * \returns Always 0, or so it seems.
978  */
979 static int read_agent_config(int reload)
980 {
981         struct ast_config *cfg;
982         struct ast_config *ucfg;
983         struct ast_variable *v;
984         struct agent_pvt *p;
985         const char *general_val;
986         const char *catname;
987         const char *hasagent;
988         int genhasagent;
989         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
990
991         group = 0;
992         autologoff = 0;
993         wrapuptime = 0;
994         ackcall = 0;
995         endcall = 1;
996         cfg = ast_config_load(config, config_flags);
997         if (!cfg) {
998                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
999                 return 0;
1000         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
1001                 return -1;
1002         AST_LIST_LOCK(&agents);
1003         AST_LIST_TRAVERSE(&agents, p, list) {
1004                 p->dead = 1;
1005         }
1006         strcpy(moh, "default");
1007         /* set the default recording values */
1008         recordagentcalls = 0;
1009         strcpy(recordformat, "wav");
1010         strcpy(recordformatext, "wav");
1011         urlprefix[0] = '\0';
1012         savecallsin[0] = '\0';
1013
1014         /* Read in [general] section for persistence */
1015         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1016                 persistent_agents = ast_true(general_val);
1017         multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1018
1019         /* Read in the [agents] section */
1020         v = ast_variable_browse(cfg, "agents");
1021         while(v) {
1022                 /* Create the interface list */
1023                 if (!strcasecmp(v->name, "agent")) {
1024                         add_agent(v->value, 0);
1025                 } else if (!strcasecmp(v->name, "group")) {
1026                         group = ast_get_group(v->value);
1027                 } else if (!strcasecmp(v->name, "autologoff")) {
1028                         autologoff = atoi(v->value);
1029                         if (autologoff < 0)
1030                                 autologoff = 0;
1031                 } else if (!strcasecmp(v->name, "ackcall")) {
1032                         if (!strcasecmp(v->value, "always"))
1033                                 ackcall = 2;
1034                         else if (ast_true(v->value))
1035                                 ackcall = 1;
1036                         else
1037                                 ackcall = 0;
1038                 } else if (!strcasecmp(v->name, "endcall")) {
1039                         endcall = ast_true(v->value);
1040                 } else if (!strcasecmp(v->name, "wrapuptime")) {
1041                         wrapuptime = atoi(v->value);
1042                         if (wrapuptime < 0)
1043                                 wrapuptime = 0;
1044                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1045                         maxlogintries = atoi(v->value);
1046                         if (maxlogintries < 0)
1047                                 maxlogintries = 0;
1048                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1049                         strcpy(agentgoodbye,v->value);
1050                 } else if (!strcasecmp(v->name, "musiconhold")) {
1051                         ast_copy_string(moh, v->value, sizeof(moh));
1052                 } else if (!strcasecmp(v->name, "updatecdr")) {
1053                         if (ast_true(v->value))
1054                                 updatecdr = 1;
1055                         else
1056                                 updatecdr = 0;
1057                 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1058                         if (ast_true(v->value))
1059                                 autologoffunavail = 1;
1060                         else
1061                                 autologoffunavail = 0;
1062                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1063                         recordagentcalls = ast_true(v->value);
1064                 } else if (!strcasecmp(v->name, "recordformat")) {
1065                         ast_copy_string(recordformat, v->value, sizeof(recordformat));
1066                         if (!strcasecmp(v->value, "wav49"))
1067                                 strcpy(recordformatext, "WAV");
1068                         else
1069                                 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1070                 } else if (!strcasecmp(v->name, "urlprefix")) {
1071                         ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1072                         if (urlprefix[strlen(urlprefix) - 1] != '/')
1073                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1074                 } else if (!strcasecmp(v->name, "savecallsin")) {
1075                         if (v->value[0] == '/')
1076                                 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1077                         else
1078                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1079                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1080                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1081                 } else if (!strcasecmp(v->name, "custom_beep")) {
1082                         ast_copy_string(beep, v->value, sizeof(beep));
1083                 }
1084                 v = v->next;
1085         }
1086         if ((ucfg = ast_config_load("users.conf", config_flags)) && ucfg != CONFIG_STATUS_FILEUNCHANGED) {
1087                 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1088                 catname = ast_category_browse(ucfg, NULL);
1089                 while(catname) {
1090                         if (strcasecmp(catname, "general")) {
1091                                 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1092                                 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1093                                         char tmp[256];
1094                                         const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1095                                         const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1096                                         if (!fullname)
1097                                                 fullname = "";
1098                                         if (!secret)
1099                                                 secret = "";
1100                                         snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1101                                         add_agent(tmp, 0);
1102                                 }
1103                         }
1104                         catname = ast_category_browse(ucfg, catname);
1105                 }
1106                 ast_config_destroy(ucfg);
1107         }
1108         AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1109                 if (p->dead) {
1110                         AST_LIST_REMOVE_CURRENT(&agents, list);
1111                         /* Destroy if  appropriate */
1112                         if (!p->owner) {
1113                                 if (!p->chan) {
1114                                         ast_mutex_destroy(&p->lock);
1115                                         ast_mutex_destroy(&p->app_lock);
1116                                         ast_free(p);
1117                                 } else {
1118                                         /* Cause them to hang up */
1119                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1120                                 }
1121                         }
1122                 }
1123         }
1124         AST_LIST_TRAVERSE_SAFE_END
1125         AST_LIST_UNLOCK(&agents);
1126         ast_config_destroy(cfg);
1127         return 1;
1128 }
1129
1130 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1131 {
1132         struct ast_channel *chan=NULL, *parent=NULL;
1133         struct agent_pvt *p;
1134         int res;
1135
1136         ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
1137         if (needlock)
1138                 AST_LIST_LOCK(&agents);
1139         AST_LIST_TRAVERSE(&agents, p, list) {
1140                 if (p == newlyavailable) {
1141                         continue;
1142                 }
1143                 ast_mutex_lock(&p->lock);
1144                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1145                         ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1146                         /* We found a pending call, time to merge */
1147                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
1148                         parent = p->owner;
1149                         p->abouttograb = 1;
1150                         ast_mutex_unlock(&p->lock);
1151                         break;
1152                 }
1153                 ast_mutex_unlock(&p->lock);
1154         }
1155         if (needlock)
1156                 AST_LIST_UNLOCK(&agents);
1157         if (parent && chan)  {
1158                 if (newlyavailable->ackcall > 1) {
1159                         /* Don't do beep here */
1160                         res = 0;
1161                 } else {
1162                         ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1163                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1164                         ast_debug(3, "Played beep, result '%d'\n", res);
1165                         if (!res) {
1166                                 res = ast_waitstream(newlyavailable->chan, "");
1167                                 ast_debug(1, "Waited for stream, result '%d'\n", res);
1168                         }
1169                 }
1170                 if (!res) {
1171                         /* Note -- parent may have disappeared */
1172                         if (p->abouttograb) {
1173                                 newlyavailable->acknowledged = 1;
1174                                 /* Safe -- agent lock already held */
1175                                 ast_setstate(parent, AST_STATE_UP);
1176                                 ast_setstate(chan, AST_STATE_UP);
1177                                 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1178                                 /* Go ahead and mark the channel as a zombie so that masquerade will
1179                                    destroy it for us, and we need not call ast_hangup */
1180                                 ast_mutex_lock(&parent->lock);
1181                                 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1182                                 ast_channel_masquerade(parent, chan);
1183                                 ast_mutex_unlock(&parent->lock);
1184                                 p->abouttograb = 0;
1185                         } else {
1186                                 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1187                                 agent_cleanup(newlyavailable);
1188                         }
1189                 } else {
1190                         ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
1191                         agent_cleanup(newlyavailable);
1192                 }
1193         }
1194         return 0;
1195 }
1196
1197 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1198 {
1199         struct agent_pvt *p;
1200         int res=0;
1201
1202         ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1203         if (needlock)
1204                 AST_LIST_LOCK(&agents);
1205         AST_LIST_TRAVERSE(&agents, p, list) {
1206                 if (p == newlyavailable) {
1207                         continue;
1208                 }
1209                 ast_mutex_lock(&p->lock);
1210                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1211                         ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1212                         ast_mutex_unlock(&p->lock);
1213                         break;
1214                 }
1215                 ast_mutex_unlock(&p->lock);
1216         }
1217         if (needlock)
1218                 AST_LIST_UNLOCK(&agents);
1219         if (p) {
1220                 ast_mutex_unlock(&newlyavailable->lock);
1221                 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1222                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1223                 ast_debug(1, "Played beep, result '%d'\n", res);
1224                 if (!res) {
1225                         res = ast_waitstream(newlyavailable->chan, "");
1226                         ast_debug(1, "Waited for stream, result '%d'\n", res);
1227                 }
1228                 ast_mutex_lock(&newlyavailable->lock);
1229         }
1230         return res;
1231 }
1232
1233 /*! \brief Part of the Asterisk PBX interface */
1234 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1235 {
1236         struct agent_pvt *p;
1237         struct ast_channel *chan = NULL;
1238         char *s;
1239         ast_group_t groupmatch;
1240         int groupoff;
1241         int waitforagent=0;
1242         int hasagent = 0;
1243         struct timeval tv;
1244
1245         s = data;
1246         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1247                 groupmatch = (1 << groupoff);
1248         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1249                 groupmatch = (1 << groupoff);
1250                 waitforagent = 1;
1251         } else 
1252                 groupmatch = 0;
1253
1254         /* Check actual logged in agents first */
1255         AST_LIST_LOCK(&agents);
1256         AST_LIST_TRAVERSE(&agents, p, list) {
1257                 ast_mutex_lock(&p->lock);
1258                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1259                     ast_strlen_zero(p->loginchan)) {
1260                         if (p->chan)
1261                                 hasagent++;
1262                         tv = ast_tvnow();
1263                         if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
1264                                 p->lastdisc = ast_tv(0, 0);
1265                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1266                                 if (!p->owner && p->chan) {
1267                                         /* Fixed agent */
1268                                         chan = agent_new(p, AST_STATE_DOWN);
1269                                 }
1270                                 if (chan) {
1271                                         ast_mutex_unlock(&p->lock);
1272                                         break;
1273                                 }
1274                         }
1275                 }
1276                 ast_mutex_unlock(&p->lock);
1277         }
1278         if (!p) {
1279                 AST_LIST_TRAVERSE(&agents, p, list) {
1280                         ast_mutex_lock(&p->lock);
1281                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1282                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1283                                         hasagent++;
1284                                 tv = ast_tvnow();
1285 #if 0
1286                                 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1287 #endif
1288                                 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
1289                                         p->lastdisc = ast_tv(0, 0);
1290                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1291                                         if (!p->owner && p->chan) {
1292                                                 /* Could still get a fixed agent */
1293                                                 chan = agent_new(p, AST_STATE_DOWN);
1294                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1295                                                 /* Adjustable agent */
1296                                                 p->chan = ast_request("Local", format, p->loginchan, cause);
1297                                                 if (p->chan)
1298                                                         chan = agent_new(p, AST_STATE_DOWN);
1299                                         }
1300                                         if (chan) {
1301                                                 ast_mutex_unlock(&p->lock);
1302                                                 break;
1303                                         }
1304                                 }
1305                         }
1306                         ast_mutex_unlock(&p->lock);
1307                 }
1308         }
1309
1310         if (!chan && waitforagent) {
1311                 /* No agent available -- but we're requesting to wait for one.
1312                    Allocate a place holder */
1313                 if (hasagent) {
1314                         ast_debug(1, "Creating place holder for '%s'\n", s);
1315                         p = add_agent(data, 1);
1316                         p->group = groupmatch;
1317                         chan = agent_new(p, AST_STATE_DOWN);
1318                         if (!chan) 
1319                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1320                 } else {
1321                         ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1322                 }
1323         }
1324         *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1325         AST_LIST_UNLOCK(&agents);
1326         return chan;
1327 }
1328
1329 static force_inline int powerof(unsigned int d)
1330 {
1331         int x = ffs(d);
1332
1333         if (x)
1334                 return x - 1;
1335
1336         return 0;
1337 }
1338
1339 /*!
1340  * Lists agents and their status to the Manager API.
1341  * It is registered on load_module() and it gets called by the manager backend.
1342  * \param s
1343  * \param m
1344  * \returns 
1345  * \sa action_agent_logoff(), load_module().
1346  */
1347 static int action_agents(struct mansession *s, const struct message *m)
1348 {
1349         const char *id = astman_get_header(m,"ActionID");
1350         char idText[256] = "";
1351         char chanbuf[256];
1352         struct agent_pvt *p;
1353         char *username = NULL;
1354         char *loginChan = NULL;
1355         char *talkingto = 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                         talkingto = "n/a";
1380                         talkingtoChan = "n/a";
1381                         status = "AGENT_IDLE";
1382                         if (p->acknowledged) {
1383                                 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
1384                                 loginChan = chanbuf;
1385                         }
1386                 } else if (p->chan) {
1387                         loginChan = ast_strdupa(p->chan->name);
1388                         if (p->owner && p->owner->_bridge) {
1389                                 talkingto = p->chan->cid.cid_num;
1390                                 if (ast_bridged_channel(p->owner))
1391                                         talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name);
1392                                 else
1393                                         talkingtoChan = "n/a";
1394                                 status = "AGENT_ONCALL";
1395                         } else {
1396                                 talkingto = "n/a";
1397                                 talkingtoChan = "n/a";
1398                                 status = "AGENT_IDLE";
1399                         }
1400                 } else {
1401                         loginChan = "n/a";
1402                         talkingto = "n/a";
1403                         talkingtoChan = "n/a";
1404                         status = "AGENT_LOGGEDOFF";
1405                 }
1406
1407                 astman_append(s, "Event: Agents\r\n"
1408                         "Agent: %s\r\n"
1409                         "Name: %s\r\n"
1410                         "Status: %s\r\n"
1411                         "LoggedInChan: %s\r\n"
1412                         "LoggedInTime: %d\r\n"
1413                         "TalkingTo: %s\r\n"
1414                         "TalkingToChan: %s\r\n"
1415                         "%s"
1416                         "\r\n",
1417                         p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1418                 ast_mutex_unlock(&p->lock);
1419         }
1420         AST_LIST_UNLOCK(&agents);
1421         astman_append(s, "Event: AgentsComplete\r\n"
1422                 "%s"
1423                 "\r\n",idText);
1424         return 0;
1425 }
1426
1427 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
1428 {
1429         char *tmp = NULL;
1430         char agent[AST_MAX_AGENT];
1431
1432         if (!ast_strlen_zero(logcommand))
1433                 tmp = logcommand;
1434         else
1435                 tmp = ast_strdupa("");
1436
1437         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1438
1439         if (!ast_strlen_zero(uniqueid)) {
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                                 "Uniqueid: %s\r\n", 
1446                                 p->agent, tmp, loginchan, logintime, uniqueid);
1447         } else {
1448                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1449                                 "Agent: %s\r\n"
1450                                 "Reason: %s\r\n"
1451                                 "Loginchan: %s\r\n"
1452                                 "Logintime: %ld\r\n",
1453                                 p->agent, tmp, loginchan, logintime);
1454         }
1455
1456         ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
1457         set_agentbycallerid(p->logincallerid, NULL);
1458         p->loginchan[0] ='\0';
1459         p->logincallerid[0] = '\0';
1460         ast_device_state_changed("Agent/%s", p->agent);
1461         if (persistent_agents)
1462                 dump_agents();  
1463
1464 }
1465
1466 static int agent_logoff(const char *agent, int soft)
1467 {
1468         struct agent_pvt *p;
1469         long logintime;
1470         int ret = -1; /* Return -1 if no agent if found */
1471
1472         AST_LIST_TRAVERSE(&agents, p, list) {
1473                 if (!strcasecmp(p->agent, agent)) {
1474                         ret = 0;
1475                         if (p->owner || p->chan) {
1476                                 if (!soft) {
1477                                         if (p->owner)
1478                                                 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1479                                         if (p->chan)
1480                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1481                                 } else
1482                                         p->deferlogoff = 1;
1483                         } else {
1484                                 logintime = time(NULL) - p->loginstart;
1485                                 p->loginstart = 0;
1486                                 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
1487                         }
1488                         break;
1489                 }
1490         }
1491
1492         return ret;
1493 }
1494
1495 static int agent_logoff_cmd(int fd, int argc, char **argv)
1496 {
1497         int ret;
1498         char *agent;
1499
1500         if (argc < 3 || argc > 4)
1501                 return RESULT_SHOWUSAGE;
1502         if (argc == 4 && strcasecmp(argv[3], "soft"))
1503                 return RESULT_SHOWUSAGE;
1504
1505         agent = argv[2] + 6;
1506         ret = agent_logoff(agent, argc == 4);
1507         if (ret == 0)
1508                 ast_cli(fd, "Logging out %s\n", agent);
1509
1510         return RESULT_SUCCESS;
1511 }
1512
1513 /*!
1514  * Sets an agent as no longer logged in in the Manager API.
1515  * It is registered on load_module() and it gets called by the manager backend.
1516  * \param s
1517  * \param m
1518  * \returns 
1519  * \sa action_agents(), load_module().
1520  */
1521 static int action_agent_logoff(struct mansession *s, const struct message *m)
1522 {
1523         const char *agent = astman_get_header(m, "Agent");
1524         const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1525         int soft;
1526         int ret; /* return value of agent_logoff */
1527
1528         if (ast_strlen_zero(agent)) {
1529                 astman_send_error(s, m, "No agent specified");
1530                 return 0;
1531         }
1532
1533         soft = ast_true(soft_s) ? 1 : 0;
1534         ret = agent_logoff(agent, soft);
1535         if (ret == 0)
1536                 astman_send_ack(s, m, "Agent logged out");
1537         else
1538                 astman_send_error(s, m, "No such agent");
1539
1540         return 0;
1541 }
1542
1543 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1544 {
1545         if (pos == 2) {
1546                 struct agent_pvt *p;
1547                 char name[AST_MAX_AGENT];
1548                 int which = 0, len = strlen(word);
1549
1550                 AST_LIST_TRAVERSE(&agents, p, list) {
1551                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1552                         if (!strncasecmp(word, name, len) && p->loginstart && ++which > state)
1553                                 return ast_strdup(name);
1554                 }
1555         } else if (pos == 3 && state == 0) 
1556                 return ast_strdup("soft");
1557         
1558         return NULL;
1559 }
1560
1561 /*!
1562  * Show agents in cli.
1563  */
1564 static int agents_show(int fd, int argc, char **argv)
1565 {
1566         struct agent_pvt *p;
1567         char username[AST_MAX_BUF];
1568         char location[AST_MAX_BUF] = "";
1569         char talkingto[AST_MAX_BUF] = "";
1570         char moh[AST_MAX_BUF];
1571         int count_agents = 0;           /*!< Number of agents configured */
1572         int online_agents = 0;          /*!< Number of online agents */
1573         int offline_agents = 0;         /*!< Number of offline agents */
1574         if (argc != 2)
1575                 return RESULT_SHOWUSAGE;
1576         AST_LIST_LOCK(&agents);
1577         AST_LIST_TRAVERSE(&agents, p, list) {
1578                 ast_mutex_lock(&p->lock);
1579                 if (p->pending) {
1580                         if (p->group)
1581                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1582                         else
1583                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1584                 } else {
1585                         if (!ast_strlen_zero(p->name))
1586                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1587                         else
1588                                 username[0] = '\0';
1589                         if (p->chan) {
1590                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1591                                 if (p->owner && ast_bridged_channel(p->owner))
1592                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1593                                  else 
1594                                         strcpy(talkingto, " is idle");
1595                                 online_agents++;
1596                         } else if (!ast_strlen_zero(p->loginchan)) {
1597                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
1598                                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1599                                 else 
1600                                         snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
1601                                 talkingto[0] = '\0';
1602                                 online_agents++;
1603                                 if (p->acknowledged)
1604                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1605                         } else {
1606                                 strcpy(location, "not logged in");
1607                                 talkingto[0] = '\0';
1608                                 offline_agents++;
1609                         }
1610                         if (!ast_strlen_zero(p->moh))
1611                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1612                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1613                                 username, location, talkingto, moh);
1614                         count_agents++;
1615                 }
1616                 ast_mutex_unlock(&p->lock);
1617         }
1618         AST_LIST_UNLOCK(&agents);
1619         if ( !count_agents ) 
1620                 ast_cli(fd, "No Agents are configured in %s\n",config);
1621         else 
1622                 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1623         ast_cli(fd, "\n");
1624                         
1625         return RESULT_SUCCESS;
1626 }
1627
1628
1629 static int agents_show_online(int fd, int argc, char **argv)
1630 {
1631         struct agent_pvt *p;
1632         char username[AST_MAX_BUF];
1633         char location[AST_MAX_BUF] = "";
1634         char talkingto[AST_MAX_BUF] = "";
1635         char moh[AST_MAX_BUF];
1636         int count_agents = 0;           /* Number of agents configured */
1637         int online_agents = 0;          /* Number of online agents */
1638         int agent_status = 0;           /* 0 means offline, 1 means online */
1639         if (argc != 3)
1640                 return RESULT_SHOWUSAGE;
1641         AST_LIST_LOCK(&agents);
1642         AST_LIST_TRAVERSE(&agents, p, list) {
1643                 agent_status = 0;       /* reset it to offline */
1644                 ast_mutex_lock(&p->lock);
1645                 if (!ast_strlen_zero(p->name))
1646                         snprintf(username, sizeof(username), "(%s) ", p->name);
1647                 else
1648                         username[0] = '\0';
1649                 if (p->chan) {
1650                         snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1651                         if (p->owner && ast_bridged_channel(p->owner)) 
1652                                 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1653                         else 
1654                                 strcpy(talkingto, " is idle");
1655                         agent_status = 1;
1656                         online_agents++;
1657                 } else if (!ast_strlen_zero(p->loginchan)) {
1658                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1659                         talkingto[0] = '\0';
1660                         agent_status = 1;
1661                         online_agents++;
1662                         if (p->acknowledged)
1663                                 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1664                 }
1665                 if (!ast_strlen_zero(p->moh))
1666                         snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1667                 if (agent_status)
1668                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
1669                 count_agents++;
1670                 ast_mutex_unlock(&p->lock);
1671         }
1672         AST_LIST_UNLOCK(&agents);
1673         if (!count_agents) 
1674                 ast_cli(fd, "No Agents are configured in %s\n", config);
1675         else
1676                 ast_cli(fd, "%d agents online\n", online_agents);
1677         ast_cli(fd, "\n");
1678         return RESULT_SUCCESS;
1679 }
1680
1681
1682
1683 static const char show_agents_usage[] = 
1684 "Usage: agent show\n"
1685 "       Provides summary information on agents.\n";
1686
1687 static const char show_agents_online_usage[] =
1688 "Usage: agent show online\n"
1689 "       Provides a list of all online agents.\n";
1690
1691 static const char agent_logoff_usage[] =
1692 "Usage: agent logoff <channel> [soft]\n"
1693 "       Sets an agent as no longer logged in.\n"
1694 "       If 'soft' is specified, do not hangup existing calls.\n";
1695
1696 static struct ast_cli_entry cli_agents[] = {
1697         { { "agent", "show", NULL },
1698         agents_show, "Show status of agents",
1699         show_agents_usage },
1700
1701         { { "agent", "show", "online" },
1702         agents_show_online, "Show all online agents",
1703         show_agents_online_usage },
1704
1705         { { "agent", "logoff", NULL },
1706         agent_logoff_cmd, "Sets an agent offline",
1707         agent_logoff_usage, complete_agent_logoff_cmd },
1708 };
1709
1710 /*!
1711  * Called by the AgentLogin application (from the dial plan).
1712  * 
1713  * \brief Log in agent application.
1714  *
1715  * \param chan
1716  * \param data
1717  * \returns
1718  * \sa agentmonitoroutgoing_exec(), load_module().
1719  */
1720 static int login_exec(struct ast_channel *chan, void *data)
1721 {
1722         int res=0;
1723         int tries = 0;
1724         int max_login_tries = maxlogintries;
1725         struct agent_pvt *p;
1726         struct ast_module_user *u;
1727         int login_state = 0;
1728         char user[AST_MAX_AGENT] = "";
1729         char pass[AST_MAX_AGENT];
1730         char agent[AST_MAX_AGENT] = "";
1731         char xpass[AST_MAX_AGENT] = "";
1732         char *errmsg;
1733         char *parse;
1734         AST_DECLARE_APP_ARGS(args,
1735                              AST_APP_ARG(agent_id);
1736                              AST_APP_ARG(options);
1737                              AST_APP_ARG(extension);
1738                 );
1739         const char *tmpoptions = NULL;
1740         int play_announcement = 1;
1741         char agent_goodbye[AST_MAX_FILENAME_LEN];
1742         int update_cdr = updatecdr;
1743         char *filename = "agent-loginok";
1744
1745         u = ast_module_user_add(chan);
1746
1747         parse = ast_strdupa(data);
1748
1749         AST_STANDARD_APP_ARGS(args, parse);
1750
1751         ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1752
1753         /* Set Channel Specific Login Overrides */
1754         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1755                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1756                 if (max_login_tries < 0)
1757                         max_login_tries = 0;
1758                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1759                 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1760         }
1761         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1762                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1763                         update_cdr = 1;
1764                 else
1765                         update_cdr = 0;
1766                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1767                 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1768         }
1769         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1770                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1771                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1772                 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1773         }
1774         /* End Channel Specific Login Overrides */
1775         
1776         if (!ast_strlen_zero(args.options)) {
1777                 if (strchr(args.options, 's')) {
1778                         play_announcement = 0;
1779                 }
1780         }
1781
1782         if (chan->_state != AST_STATE_UP)
1783                 res = ast_answer(chan);
1784         if (!res) {
1785                 if (!ast_strlen_zero(args.agent_id))
1786                         ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1787                 else
1788                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1789         }
1790         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1791                 tries++;
1792                 /* Check for password */
1793                 AST_LIST_LOCK(&agents);
1794                 AST_LIST_TRAVERSE(&agents, p, list) {
1795                         if (!strcmp(p->agent, user) && !p->pending)
1796                                 ast_copy_string(xpass, p->password, sizeof(xpass));
1797                 }
1798                 AST_LIST_UNLOCK(&agents);
1799                 if (!res) {
1800                         if (!ast_strlen_zero(xpass))
1801                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1802                         else
1803                                 pass[0] = '\0';
1804                 }
1805                 errmsg = "agent-incorrect";
1806
1807 #if 0
1808                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1809 #endif          
1810
1811                 /* Check again for accuracy */
1812                 AST_LIST_LOCK(&agents);
1813                 AST_LIST_TRAVERSE(&agents, p, list) {
1814                         ast_mutex_lock(&p->lock);
1815                         if (!strcmp(p->agent, user) &&
1816                             !strcmp(p->password, pass) && !p->pending) {
1817                                 login_state = 1; /* Successful Login */
1818
1819                                 /* Ensure we can't be gotten until we're done */
1820                                 p->lastdisc = ast_tvnow();
1821                                 p->lastdisc.tv_sec++;
1822
1823                                 /* Set Channel Specific Agent Overrides */
1824                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1825                                         if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1826                                                 p->ackcall = 2;
1827                                         else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1828                                                 p->ackcall = 1;
1829                                         else
1830                                                 p->ackcall = 0;
1831                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1832                                         ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1833                                 }
1834                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1835                                         p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1836                                         if (p->autologoff < 0)
1837                                                 p->autologoff = 0;
1838                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1839                                         ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1840                                 }
1841                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1842                                         p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1843                                         if (p->wrapuptime < 0)
1844                                                 p->wrapuptime = 0;
1845                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1846                                         ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1847                                 }
1848                                 /* End Channel Specific Agent Overrides */
1849                                 if (!p->chan) {
1850                                         long logintime;
1851                                         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1852
1853                                         p->loginchan[0] = '\0';
1854                                         p->logincallerid[0] = '\0';
1855                                         p->acknowledged = 0;
1856                                         
1857                                         ast_mutex_unlock(&p->lock);
1858                                         AST_LIST_UNLOCK(&agents);
1859                                         if( !res && play_announcement==1 )
1860                                                 res = ast_streamfile(chan, filename, chan->language);
1861                                         if (!res)
1862                                                 ast_waitstream(chan, "");
1863                                         AST_LIST_LOCK(&agents);
1864                                         ast_mutex_lock(&p->lock);
1865                                         if (!res) {
1866                                                 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1867                                                 if (res)
1868                                                         ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1869                                         }
1870                                         if (!res) {
1871                                                 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1872                                                 if (res)
1873                                                         ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1874                                         }
1875                                         /* Check once more just in case */
1876                                         if (p->chan)
1877                                                 res = -1;
1878                                         if (!res) {
1879                                                 ast_indicate_data(chan, AST_CONTROL_HOLD, 
1880                                                         S_OR(p->moh, NULL), 
1881                                                         !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
1882                                                 if (p->loginstart == 0)
1883                                                         time(&p->loginstart);
1884                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1885                                                               "Agent: %s\r\n"
1886                                                               "Channel: %s\r\n"
1887                                                               "Uniqueid: %s\r\n",
1888                                                               p->agent, chan->name, chan->uniqueid);
1889                                                 if (update_cdr && chan->cdr)
1890                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1891                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1892                                                 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
1893                                                                     ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1894                                                 /* Login this channel and wait for it to go away */
1895                                                 p->chan = chan;
1896                                                 if (p->ackcall > 1)
1897                                                         check_beep(p, 0);
1898                                                 else
1899                                                         check_availability(p, 0);
1900                                                 ast_mutex_unlock(&p->lock);
1901                                                 AST_LIST_UNLOCK(&agents);
1902                                                 ast_device_state_changed("Agent/%s", p->agent);
1903                                                 while (res >= 0) {
1904                                                         ast_mutex_lock(&p->lock);
1905                                                         if (p->deferlogoff && p->chan) {
1906                                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1907                                                                 p->deferlogoff = 0;
1908                                                         }
1909                                                         if (p->chan != chan)
1910                                                                 res = -1;
1911                                                         ast_mutex_unlock(&p->lock);
1912                                                         /* Yield here so other interested threads can kick in. */
1913                                                         sched_yield();
1914                                                         if (res)
1915                                                                 break;
1916
1917                                                         AST_LIST_LOCK(&agents);
1918                                                         ast_mutex_lock(&p->lock);
1919                                                         if (p->lastdisc.tv_sec) {
1920                                                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
1921                                                                         ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
1922                                                                         p->lastdisc = ast_tv(0, 0);
1923                                                                         ast_device_state_changed("Agent/%s", p->agent);
1924                                                                         if (p->ackcall > 1)
1925                                                                                 check_beep(p, 0);
1926                                                                         else
1927                                                                                 check_availability(p, 0);
1928                                                                 }
1929                                                         }
1930                                                         ast_mutex_unlock(&p->lock);
1931                                                         AST_LIST_UNLOCK(&agents);
1932                                                         /*      Synchronize channel ownership between call to agent and itself. */
1933                                                         ast_mutex_lock( &p->app_lock );
1934                                                         ast_mutex_lock(&p->lock);
1935                                                         p->owning_app = pthread_self();
1936                                                         ast_mutex_unlock(&p->lock);
1937                                                         if (p->ackcall > 1) 
1938                                                                 res = agent_ack_sleep(p);
1939                                                         else
1940                                                                 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
1941                                                         ast_mutex_unlock( &p->app_lock );
1942                                                         if ((p->ackcall > 1)  && (res == 1)) {
1943                                                                 AST_LIST_LOCK(&agents);
1944                                                                 ast_mutex_lock(&p->lock);
1945                                                                 check_availability(p, 0);
1946                                                                 ast_mutex_unlock(&p->lock);
1947                                                                 AST_LIST_UNLOCK(&agents);
1948                                                                 res = 0;
1949                                                         }
1950                                                         sched_yield();
1951                                                 }
1952                                                 ast_mutex_lock(&p->lock);
1953                                                 if (res && p->owner) 
1954                                                         ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1955                                                 /* Log us off if appropriate */
1956                                                 if (p->chan == chan)
1957                                                         p->chan = NULL;
1958                                                 p->acknowledged = 0;
1959                                                 logintime = time(NULL) - p->loginstart;
1960                                                 p->loginstart = 0;
1961                                                 ast_mutex_unlock(&p->lock);
1962                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1963                                                               "Agent: %s\r\n"
1964                                                               "Logintime: %ld\r\n"
1965                                                               "Uniqueid: %s\r\n",
1966                                                               p->agent, logintime, chan->uniqueid);
1967                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1968                                                 ast_verb(2, "Agent '%s' logged out\n", p->agent);
1969                                                 /* If there is no owner, go ahead and kill it now */
1970                                                 ast_device_state_changed("Agent/%s", p->agent);
1971                                                 if (p->dead && !p->owner) {
1972                                                         ast_mutex_destroy(&p->lock);
1973                                                         ast_mutex_destroy(&p->app_lock);
1974                                                         ast_free(p);
1975                                                 }
1976                                         }
1977                                         else {
1978                                                 ast_mutex_unlock(&p->lock);
1979                                                 p = NULL;
1980                                         }
1981                                         res = -1;
1982                                 } else {
1983                                         ast_mutex_unlock(&p->lock);
1984                                         errmsg = "agent-alreadyon";
1985                                         p = NULL;
1986                                 }
1987                                 break;
1988                         }
1989                         ast_mutex_unlock(&p->lock);
1990                 }
1991                 if (!p)
1992                         AST_LIST_UNLOCK(&agents);
1993
1994                 if (!res && (max_login_tries==0 || tries < max_login_tries))
1995                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1996         }
1997                 
1998         if (!res)
1999                 res = ast_safe_sleep(chan, 500);
2000
2001         ast_module_user_remove(u);
2002         
2003         return -1;
2004 }
2005
2006 /*!
2007  *  \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2008  *
2009  * \param chan
2010  * \param data
2011  * \returns
2012  * \sa login_exec(), load_module().
2013  */
2014 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2015 {
2016         int exitifnoagentid = 0;
2017         int nowarnings = 0;
2018         int changeoutgoing = 0;
2019         int res = 0;
2020         char agent[AST_MAX_AGENT];
2021
2022         if (data) {
2023                 if (strchr(data, 'd'))
2024                         exitifnoagentid = 1;
2025                 if (strchr(data, 'n'))
2026                         nowarnings = 1;
2027                 if (strchr(data, 'c'))
2028                         changeoutgoing = 1;
2029         }
2030         if (chan->cid.cid_num) {
2031                 const char *tmp;
2032                 char agentvar[AST_MAX_BUF];
2033                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2034                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2035                         struct agent_pvt *p;
2036                         ast_copy_string(agent, tmp, sizeof(agent));
2037                         AST_LIST_LOCK(&agents);
2038                         AST_LIST_TRAVERSE(&agents, p, list) {
2039                                 if (!strcasecmp(p->agent, tmp)) {
2040                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2041                                         __agent_start_monitoring(chan, p, 1);
2042                                         break;
2043                                 }
2044                         }
2045                         AST_LIST_UNLOCK(&agents);
2046                         
2047                 } else {
2048                         res = -1;
2049                         if (!nowarnings)
2050                                 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);
2051                 }
2052         } else {
2053                 res = -1;
2054                 if (!nowarnings)
2055                         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");
2056         }
2057         if (res) {
2058                 if (exitifnoagentid)
2059                         return res;
2060         }
2061         return 0;
2062 }
2063
2064 /*!
2065  * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
2066  */
2067 static void dump_agents(void)
2068 {
2069         struct agent_pvt *cur_agent = NULL;
2070         char buf[256];
2071
2072         AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2073                 if (cur_agent->chan)
2074                         continue;
2075
2076                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2077                         snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2078                         if (ast_db_put(pa_family, cur_agent->agent, buf))
2079                                 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
2080                         else
2081                                 ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2082                 } else {
2083                         /* Delete -  no agent or there is an error */
2084                         ast_db_del(pa_family, cur_agent->agent);
2085                 }
2086         }
2087 }
2088
2089 /*!
2090  * \brief Reload the persistent agents from astdb.
2091  */
2092 static void reload_agents(void)
2093 {
2094         char *agent_num;
2095         struct ast_db_entry *db_tree;
2096         struct ast_db_entry *entry;
2097         struct agent_pvt *cur_agent;
2098         char agent_data[256];
2099         char *parse;
2100         char *agent_chan;
2101         char *agent_callerid;
2102
2103         db_tree = ast_db_gettree(pa_family, NULL);
2104
2105         AST_LIST_LOCK(&agents);
2106         for (entry = db_tree; entry; entry = entry->next) {
2107                 agent_num = entry->key + strlen(pa_family) + 2;
2108                 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2109                         ast_mutex_lock(&cur_agent->lock);
2110                         if (strcmp(agent_num, cur_agent->agent) == 0)
2111                                 break;
2112                         ast_mutex_unlock(&cur_agent->lock);
2113                 }
2114                 if (!cur_agent) {
2115                         ast_db_del(pa_family, agent_num);
2116                         continue;
2117                 } else
2118                         ast_mutex_unlock(&cur_agent->lock);
2119                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2120                         ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
2121                         parse = agent_data;
2122                         agent_chan = strsep(&parse, ";");
2123                         agent_callerid = strsep(&parse, ";");
2124                         ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2125                         if (agent_callerid) {
2126                                 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2127                                 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2128                         } else
2129                                 cur_agent->logincallerid[0] = '\0';
2130                         if (cur_agent->loginstart == 0)
2131                                 time(&cur_agent->loginstart);
2132                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2133                 }
2134         }
2135         AST_LIST_UNLOCK(&agents);
2136         if (db_tree) {
2137                 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
2138                 ast_db_freetree(db_tree);
2139         }
2140 }
2141
2142 /*! \brief Part of PBX channel interface */
2143 static int agent_devicestate(void *data)
2144 {
2145         struct agent_pvt *p;
2146         char *s;
2147         ast_group_t groupmatch;
2148         int groupoff;
2149         int res = AST_DEVICE_INVALID;
2150         
2151         s = data;
2152         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
2153                 groupmatch = (1 << groupoff);
2154         else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2155                 groupmatch = (1 << groupoff);
2156         } else 
2157                 groupmatch = 0;
2158
2159         /* Check actual logged in agents first */
2160         AST_LIST_LOCK(&agents);
2161         AST_LIST_TRAVERSE(&agents, p, list) {
2162                 ast_mutex_lock(&p->lock);
2163                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2164                         if (p->owner) {
2165                                 if (res != AST_DEVICE_INUSE)
2166                                         res = AST_DEVICE_BUSY;
2167                         } else {
2168                                 if (res == AST_DEVICE_BUSY)
2169                                         res = AST_DEVICE_INUSE;
2170                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2171                                         if (res == AST_DEVICE_INVALID)
2172                                                 res = AST_DEVICE_UNKNOWN;
2173                                 } else if (res == AST_DEVICE_INVALID)   
2174                                         res = AST_DEVICE_UNAVAILABLE;
2175                         }
2176                         if (!strcmp(data, p->agent)) {
2177                                 ast_mutex_unlock(&p->lock);
2178                                 break;
2179                         }
2180                 }
2181                 ast_mutex_unlock(&p->lock);
2182         }
2183         AST_LIST_UNLOCK(&agents);
2184         return res;
2185 }
2186
2187 static struct agent_pvt *find_agent(char *agentid)
2188 {
2189         struct agent_pvt *cur;
2190
2191         AST_LIST_TRAVERSE(&agents, cur, list) {
2192                 if (!strcmp(cur->agent, agentid))
2193                         break;  
2194         }
2195
2196         return cur;     
2197 }
2198
2199 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2200 {
2201         char *parse;    
2202         AST_DECLARE_APP_ARGS(args,
2203                 AST_APP_ARG(agentid);
2204                 AST_APP_ARG(item);
2205         );
2206         char *tmp;
2207         struct agent_pvt *agent;
2208
2209         buf[0] = '\0';
2210
2211         if (ast_strlen_zero(data)) {
2212                 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2213                 return -1;
2214         }
2215
2216         parse = ast_strdupa(data);
2217
2218         AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2219         if (!args.item)
2220                 args.item = "status";
2221
2222         if (!(agent = find_agent(args.agentid))) {
2223                 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2224                 return -1;
2225         }
2226
2227         if (!strcasecmp(args.item, "status")) {
2228                 char *status = "LOGGEDOUT";
2229                 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
2230                         status = "LOGGEDIN";    
2231                 ast_copy_string(buf, status, len);
2232         } else if (!strcasecmp(args.item, "password")) 
2233                 ast_copy_string(buf, agent->password, len);
2234         else if (!strcasecmp(args.item, "name"))
2235                 ast_copy_string(buf, agent->name, len);
2236         else if (!strcasecmp(args.item, "mohclass"))
2237                 ast_copy_string(buf, agent->moh, len);
2238         else if (!strcasecmp(args.item, "channel")) {
2239                 if (agent->chan) {
2240                         ast_copy_string(buf, agent->chan->name, len);
2241                         tmp = strrchr(buf, '-');
2242                         if (tmp)
2243                                 *tmp = '\0';
2244                 } 
2245         } else if (!strcasecmp(args.item, "exten"))
2246                 ast_copy_string(buf, agent->loginchan, len);    
2247
2248         return 0;
2249 }
2250
2251 struct ast_custom_function agent_function = {
2252         .name = "AGENT",
2253         .synopsis = "Gets information about an Agent",
2254         .syntax = "AGENT(<agentid>[:item])",
2255         .read = function_agent,
2256         .desc = "The valid items to retrieve are:\n"
2257         "- status (default)      The status of the agent\n"
2258         "                          LOGGEDIN | LOGGEDOUT\n"
2259         "- password              The password of the agent\n"
2260         "- name                  The name of the agent\n"
2261         "- mohclass              MusicOnHold class\n"
2262         "- exten                 The callback extension for the Agent (AgentCallbackLogin)\n"
2263         "- channel               The name of the active channel for the Agent (AgentLogin)\n"
2264 };
2265
2266
2267 /*!
2268  * \brief Initialize the Agents module.
2269  * This function is being called by Asterisk when loading the module. 
2270  * Among other things it registers applications, cli commands and reads the cofiguration file.
2271  *
2272  * \returns int Always 0.
2273  */
2274 static int load_module(void)
2275 {
2276         /* Make sure we can register our agent channel type */
2277         if (ast_channel_register(&agent_tech)) {
2278                 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2279                 return -1;
2280         }
2281         /* Read in the config */
2282         if (!read_agent_config(0))
2283                 return AST_MODULE_LOAD_DECLINE;
2284         if (persistent_agents)
2285                 reload_agents();
2286         /* Dialplan applications */
2287         ast_register_application(app, login_exec, synopsis, descrip);
2288         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2289
2290         /* Manager commands */
2291         ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2292         ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2293
2294         /* CLI Commands */
2295         ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2296
2297         /* Dialplan Functions */
2298         ast_custom_function_register(&agent_function);
2299
2300         return 0;
2301 }
2302
2303 static int reload(void)
2304 {
2305         if (!read_agent_config(1)) {
2306                 if (persistent_agents)
2307                         reload_agents();
2308         }
2309         return 0;
2310 }
2311
2312 static int unload_module(void)
2313 {
2314         struct agent_pvt *p;
2315         /* First, take us out of the channel loop */
2316         ast_channel_unregister(&agent_tech);
2317         /* Unregister dialplan functions */
2318         ast_custom_function_unregister(&agent_function);        
2319         /* Unregister CLI commands */
2320         ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2321         /* Unregister dialplan applications */
2322         ast_unregister_application(app);
2323         ast_unregister_application(app3);
2324         /* Unregister manager command */
2325         ast_manager_unregister("Agents");
2326         ast_manager_unregister("AgentLogoff");
2327         /* Unregister channel */
2328         AST_LIST_LOCK(&agents);
2329         /* Hangup all interfaces if they have an owner */
2330         while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2331                 if (p->owner)
2332                         ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2333                 ast_free(p);
2334         }
2335         AST_LIST_UNLOCK(&agents);
2336         AST_LIST_HEAD_DESTROY(&agents);
2337         return 0;
2338 }
2339
2340 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
2341                 .load = load_module,
2342                 .unload = unload_module,
2343                 .reload = reload,
2344                );