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