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