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