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