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