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