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