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