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