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