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