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