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