Clean up doxygen warnings
[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  * \ref 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, struct ast_callid *callid)
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         if (callid) {
1121                 ast_channel_callid_set(tmp, callid);
1122         }
1123
1124         ast_channel_tech_set(tmp, &agent_tech);
1125         if (p->chan) {
1126                 ast_format_cap_copy(ast_channel_nativeformats(tmp), ast_channel_nativeformats(p->chan));
1127                 ast_format_copy(ast_channel_writeformat(tmp), ast_channel_writeformat(p->chan));
1128                 ast_format_copy(ast_channel_rawwriteformat(tmp), ast_channel_writeformat(p->chan));
1129                 ast_format_copy(ast_channel_readformat(tmp), ast_channel_readformat(p->chan));
1130                 ast_format_copy(ast_channel_rawreadformat(tmp), ast_channel_readformat(p->chan));
1131                 ast_channel_language_set(tmp, ast_channel_language(p->chan));
1132                 ast_channel_context_set(tmp, ast_channel_context(p->chan));
1133                 ast_channel_exten_set(tmp, ast_channel_exten(p->chan));
1134                 /* XXX Is this really all we copy form the originating channel?? */
1135         } else {
1136                 ast_format_set(ast_channel_writeformat(tmp), AST_FORMAT_SLINEAR, 0);
1137                 ast_format_set(ast_channel_rawwriteformat(tmp), AST_FORMAT_SLINEAR, 0);
1138                 ast_format_set(ast_channel_readformat(tmp), AST_FORMAT_SLINEAR, 0);
1139                 ast_format_set(ast_channel_rawreadformat(tmp), AST_FORMAT_SLINEAR, 0);
1140                 ast_format_cap_add(ast_channel_nativeformats(tmp), ast_channel_writeformat(tmp));
1141         }
1142         /* Safe, agentlock already held */
1143         ast_channel_tech_pvt_set(tmp, p);
1144         p->owner = tmp;
1145         ast_channel_priority_set(tmp, 1);
1146         return tmp;
1147 }
1148
1149
1150 /*!
1151  * Read configuration data. The file named agents.conf.
1152  *
1153  * \returns Always 0, or so it seems.
1154  */
1155 static int read_agent_config(int reload)
1156 {
1157         struct ast_config *cfg;
1158         struct ast_config *ucfg;
1159         struct ast_variable *v;
1160         struct agent_pvt *p;
1161         const char *catname;
1162         const char *hasagent;
1163         int genhasagent;
1164         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1165
1166         group = 0;
1167         autologoff = 0;
1168         wrapuptime = 0;
1169         ackcall = 0;
1170         endcall = 1;
1171         cfg = ast_config_load(config, config_flags);
1172         if (!cfg) {
1173                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1174                 return 0;
1175         } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1176                 return -1;
1177         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1178                 ast_log(LOG_ERROR, "%s contains a parsing error.  Aborting\n", config);
1179                 return 0;
1180         }
1181         if ((ucfg = ast_config_load("users.conf", config_flags))) {
1182                 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
1183                         ucfg = NULL;
1184                 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
1185                         ast_log(LOG_ERROR, "users.conf contains a parsing error.  Aborting\n");
1186                         return 0;
1187                 }
1188         }
1189
1190         AST_LIST_LOCK(&agents);
1191         AST_LIST_TRAVERSE(&agents, p, list) {
1192                 p->dead = 1;
1193         }
1194         strcpy(moh, "default");
1195         /* set the default recording values */
1196         recordagentcalls = 0;
1197         strcpy(recordformat, "wav");
1198         strcpy(recordformatext, "wav");
1199         urlprefix[0] = '\0';
1200         savecallsin[0] = '\0';
1201
1202         /* Read in [general] section for persistence */
1203         multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1204
1205         /* Read in the [agents] section */
1206         v = ast_variable_browse(cfg, "agents");
1207         while(v) {
1208                 /* Create the interface list */
1209                 if (!strcasecmp(v->name, "agent")) {
1210                         add_agent(v->value, 0);
1211                 } else if (!strcasecmp(v->name, "group")) {
1212                         group = ast_get_group(v->value);
1213                 } else if (!strcasecmp(v->name, "autologoff")) {
1214                         autologoff = atoi(v->value);
1215                         if (autologoff < 0)
1216                                 autologoff = 0;
1217                 } else if (!strcasecmp(v->name, "ackcall")) {
1218                         if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
1219                                 ackcall = 1;
1220                         }
1221                 } else if (!strcasecmp(v->name, "endcall")) {
1222                         endcall = ast_true(v->value);
1223                 } else if (!strcasecmp(v->name, "acceptdtmf")) {
1224                         acceptdtmf = *(v->value);
1225                         ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
1226                 } else if (!strcasecmp(v->name, "enddtmf")) {
1227                         enddtmf = *(v->value);
1228                 } else if (!strcasecmp(v->name, "wrapuptime")) {
1229                         wrapuptime = atoi(v->value);
1230                         if (wrapuptime < 0)
1231                                 wrapuptime = 0;
1232                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1233                         maxlogintries = atoi(v->value);
1234                         if (maxlogintries < 0)
1235                                 maxlogintries = 0;
1236                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1237                         strcpy(agentgoodbye,v->value);
1238                 } else if (!strcasecmp(v->name, "musiconhold")) {
1239                         ast_copy_string(moh, v->value, sizeof(moh));
1240                 } else if (!strcasecmp(v->name, "updatecdr")) {
1241                         if (ast_true(v->value))
1242                                 updatecdr = 1;
1243                         else
1244                                 updatecdr = 0;
1245                 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1246                         if (ast_true(v->value))
1247                                 autologoffunavail = 1;
1248                         else
1249                                 autologoffunavail = 0;
1250                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1251                         recordagentcalls = ast_true(v->value);
1252                 } else if (!strcasecmp(v->name, "recordformat")) {
1253                         ast_copy_string(recordformat, v->value, sizeof(recordformat));
1254                         if (!strcasecmp(v->value, "wav49"))
1255                                 strcpy(recordformatext, "WAV");
1256                         else
1257                                 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1258                 } else if (!strcasecmp(v->name, "urlprefix")) {
1259                         ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1260                         if (urlprefix[strlen(urlprefix) - 1] != '/')
1261                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1262                 } else if (!strcasecmp(v->name, "savecallsin")) {
1263                         if (v->value[0] == '/')
1264                                 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1265                         else
1266                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1267                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1268                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1269                 } else if (!strcasecmp(v->name, "custom_beep")) {
1270                         ast_copy_string(beep, v->value, sizeof(beep));
1271                 }
1272                 v = v->next;
1273         }
1274         if (ucfg) {
1275                 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1276                 catname = ast_category_browse(ucfg, NULL);
1277                 while(catname) {
1278                         if (strcasecmp(catname, "general")) {
1279                                 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1280                                 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1281                                         char tmp[256];
1282                                         const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1283                                         const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1284                                         if (!fullname)
1285                                                 fullname = "";
1286                                         if (!secret)
1287                                                 secret = "";
1288                                         snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1289                                         add_agent(tmp, 0);
1290                                 }
1291                         }
1292                         catname = ast_category_browse(ucfg, catname);
1293                 }
1294                 ast_config_destroy(ucfg);
1295         }
1296         AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1297                 if (p->dead) {
1298                         AST_LIST_REMOVE_CURRENT(list);
1299                         /* Destroy if  appropriate */
1300                         if (!p->owner) {
1301                                 if (!p->chan) {
1302                                         ast_mutex_destroy(&p->lock);
1303                                         ast_cond_destroy(&p->app_complete_cond);
1304                                         ast_cond_destroy(&p->login_wait_cond);
1305                                         ast_free(p);
1306                                 } else {
1307                                         /* Cause them to hang up */
1308                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1309                                 }
1310                         }
1311                 }
1312         }
1313         AST_LIST_TRAVERSE_SAFE_END;
1314         AST_LIST_UNLOCK(&agents);
1315         ast_config_destroy(cfg);
1316         return 1;
1317 }
1318
1319 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1320 {
1321         struct ast_channel *chan=NULL, *parent=NULL;
1322         struct agent_pvt *p;
1323         int res;
1324
1325         ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
1326         if (needlock)
1327                 AST_LIST_LOCK(&agents);
1328         AST_LIST_TRAVERSE(&agents, p, list) {
1329                 if (p == newlyavailable) {
1330                         continue;
1331                 }
1332                 ast_mutex_lock(&p->lock);
1333                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1334                         ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1335                         /* We found a pending call, time to merge */
1336                         chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? ast_channel_linkedid(p->owner) : NULL, NULL);
1337                         parent = p->owner;
1338                         p->abouttograb = 1;
1339                         ast_mutex_unlock(&p->lock);
1340                         break;
1341                 }
1342                 ast_mutex_unlock(&p->lock);
1343         }
1344         if (needlock)
1345                 AST_LIST_UNLOCK(&agents);
1346         if (parent && chan)  {
1347                 if (newlyavailable->ackcall) {
1348                         /* Don't do beep here */
1349                         res = 0;
1350                 } else {
1351                         ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1352                         res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1353                         ast_debug(3, "Played beep, result '%d'\n", res);
1354                         if (!res) {
1355                                 res = ast_waitstream(newlyavailable->chan, "");
1356                                 ast_debug(1, "Waited for stream, result '%d'\n", res);
1357                         }
1358                 }
1359                 if (!res) {
1360                         /* Note -- parent may have disappeared */
1361                         if (p->abouttograb) {
1362                                 newlyavailable->acknowledged = 1;
1363                                 /* Safe -- agent lock already held */
1364                                 ast_setstate(parent, AST_STATE_UP);
1365                                 ast_setstate(chan, AST_STATE_UP);
1366                                 ast_channel_context_set(parent, ast_channel_context(chan));
1367                                 ast_channel_masquerade(parent, chan);
1368                                 ast_hangup(chan);
1369                                 p->abouttograb = 0;
1370                         } else {
1371                                 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1372                                 agent_cleanup(newlyavailable);
1373                         }
1374                 } else {
1375                         ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
1376                         agent_cleanup(newlyavailable);
1377                 }
1378         }
1379         return 0;
1380 }
1381
1382 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1383 {
1384         struct agent_pvt *p;
1385         int res=0;
1386
1387         ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1388         if (needlock)
1389                 AST_LIST_LOCK(&agents);
1390         AST_LIST_TRAVERSE(&agents, p, list) {
1391                 if (p == newlyavailable) {
1392                         continue;
1393                 }
1394                 ast_mutex_lock(&p->lock);
1395                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1396                         ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1397                         ast_mutex_unlock(&p->lock);
1398                         break;
1399                 }
1400                 ast_mutex_unlock(&p->lock);
1401         }
1402         if (needlock)
1403                 AST_LIST_UNLOCK(&agents);
1404         if (p) {
1405                 ast_mutex_unlock(&newlyavailable->lock);
1406                 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1407                 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1408                 ast_debug(1, "Played beep, result '%d'\n", res);
1409                 if (!res) {
1410                         res = ast_waitstream(newlyavailable->chan, "");
1411                         ast_debug(1, "Waited for stream, result '%d'\n", res);
1412                 }
1413                 ast_mutex_lock(&newlyavailable->lock);
1414         }
1415         return res;
1416 }
1417
1418 /*! \brief Part of the Asterisk PBX interface */
1419 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel* requestor, const char *data, int *cause)
1420 {
1421         struct agent_pvt *p;
1422         struct ast_channel *chan = NULL;
1423         const char *s;
1424         ast_group_t groupmatch;
1425         int groupoff;
1426         int waitforagent=0;
1427         int hasagent = 0;
1428         struct timeval now;
1429         struct ast_callid *callid = ast_read_threadstorage_callid();
1430
1431         s = data;
1432         if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1433                 groupmatch = (1 << groupoff);
1434         } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1435                 groupmatch = (1 << groupoff);
1436                 waitforagent = 1;
1437         } else 
1438                 groupmatch = 0;
1439
1440         /* Check actual logged in agents first */
1441         AST_LIST_LOCK(&agents);
1442         AST_LIST_TRAVERSE(&agents, p, list) {
1443                 ast_mutex_lock(&p->lock);
1444                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1445                         if (p->chan)
1446                                 hasagent++;
1447                         now = ast_tvnow();
1448                         if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1449                                 p->lastdisc = ast_tv(0, 0);
1450                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1451                                 if (!p->owner && p->chan) {
1452                                         /* Fixed agent */
1453                                         chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
1454                                 }
1455                                 if (chan) {
1456                                         ast_mutex_unlock(&p->lock);
1457                                         break;
1458                                 }
1459                         }
1460                 }
1461                 ast_mutex_unlock(&p->lock);
1462         }
1463         if (!p) {
1464                 AST_LIST_TRAVERSE(&agents, p, list) {
1465                         ast_mutex_lock(&p->lock);
1466                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1467                                 if (p->chan) {
1468                                         hasagent++;
1469                                 }
1470                                 now = ast_tvnow();
1471                                 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1472                                         p->lastdisc = ast_tv(0, 0);
1473                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1474                                         if (!p->owner && p->chan) {
1475                                                 /* Could still get a fixed agent */
1476                                                 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
1477                                         }
1478                                         if (chan) {
1479                                                 ast_mutex_unlock(&p->lock);
1480                                                 break;
1481                                         }
1482                                 }
1483                         }
1484                         ast_mutex_unlock(&p->lock);
1485                 }
1486         }
1487
1488         if (!chan && waitforagent) {
1489                 /* No agent available -- but we're requesting to wait for one.
1490                    Allocate a place holder */
1491                 if (hasagent) {
1492                         ast_debug(1, "Creating place holder for '%s'\n", s);
1493                         p = add_agent(data, 1);
1494                         p->group = groupmatch;
1495                         chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
1496                         if (!chan) 
1497                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1498                 } else {
1499                         ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1500                 }
1501         }
1502         *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1503         AST_LIST_UNLOCK(&agents);
1504
1505         if (callid) {
1506                 callid = ast_callid_unref(callid);
1507         }
1508
1509         if (chan) {
1510                 ast_mutex_lock(&p->lock);
1511                 if (p->pending) {
1512                         ast_mutex_unlock(&p->lock);
1513                         return chan;
1514                 }
1515
1516                 if (!p->chan) {
1517                         ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1518                         *cause = AST_CAUSE_UNREGISTERED;
1519                         ast_mutex_unlock(&p->lock);
1520                         agent_hangup(chan);
1521                         return NULL;
1522                 }
1523
1524                 /* we need to take control of the channel from the login app
1525                  * thread */
1526                 p->app_sleep_cond = 0;
1527                 p->app_lock_flag = 1;
1528
1529                 ast_queue_frame(p->chan, &ast_null_frame);
1530                 ast_cond_wait(&p->login_wait_cond, &p->lock);
1531
1532                 if (!p->chan) {
1533                         ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1534                         p->app_sleep_cond = 1;
1535                         p->app_lock_flag = 0;
1536                         ast_cond_signal(&p->app_complete_cond);
1537                         ast_mutex_unlock(&p->lock);
1538                         *cause = AST_CAUSE_UNREGISTERED;
1539                         agent_hangup(chan);
1540                         return NULL;
1541                 }
1542
1543                 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
1544                 ast_mutex_unlock(&p->lock);
1545         }
1546
1547         return chan;
1548 }
1549
1550 static force_inline int powerof(unsigned int d)
1551 {
1552         int x = ffs(d);
1553
1554         if (x)
1555                 return x - 1;
1556
1557         return 0;
1558 }
1559
1560 /*!
1561  * Lists agents and their status to the Manager API.
1562  * It is registered on load_module() and it gets called by the manager backend.
1563  * This function locks both the pvt and the channel that owns it for a while, but
1564  * does not keep these locks.
1565  * \param s
1566  * \param m
1567  * \returns 
1568  * \sa action_agent_logoff(), load_module().
1569  */
1570 static int action_agents(struct mansession *s, const struct message *m)
1571 {
1572         const char *id = astman_get_header(m,"ActionID");
1573         char idText[256] = "";
1574         struct agent_pvt *p;
1575         char *username = NULL;
1576         char *loginChan = NULL;
1577         char *talkingto = NULL;
1578         char *talkingtoChan = NULL;
1579         char *status = NULL;
1580         struct ast_channel *bridge;
1581
1582         if (!ast_strlen_zero(id))
1583                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1584         astman_send_ack(s, m, "Agents will follow");
1585         AST_LIST_LOCK(&agents);
1586         AST_LIST_TRAVERSE(&agents, p, list) {
1587                 struct ast_channel *owner;
1588                 ast_mutex_lock(&p->lock);
1589                 owner = agent_lock_owner(p);
1590
1591                 /* Status Values:
1592                    AGENT_LOGGEDOFF - Agent isn't logged in
1593                    AGENT_IDLE      - Agent is logged in, and waiting for call
1594                    AGENT_ONCALL    - Agent is logged in, and on a call
1595                    AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1596
1597                 username = S_OR(p->name, "None");
1598
1599                 /* Set a default status. It 'should' get changed. */
1600                 status = "AGENT_UNKNOWN";
1601
1602                 if (p->chan) {
1603                         loginChan = ast_strdupa(ast_channel_name(p->chan));
1604                         if (owner && ast_channel_internal_bridged_channel(owner)) {
1605                                 talkingto = S_COR(ast_channel_caller(p->chan)->id.number.valid,
1606                                         ast_channel_caller(p->chan)->id.number.str, "n/a");
1607                                 if ((bridge = ast_bridged_channel(owner))) {
1608                                         talkingtoChan = ast_strdupa(ast_channel_name(bridge));
1609                                 } else {
1610                                         talkingtoChan = "n/a";
1611                                 }
1612                                 status = "AGENT_ONCALL";
1613                         } else {
1614                                 talkingto = "n/a";
1615                                 talkingtoChan = "n/a";
1616                                 status = "AGENT_IDLE";
1617                         }
1618                 } else {
1619                         loginChan = "n/a";
1620                         talkingto = "n/a";
1621                         talkingtoChan = "n/a";
1622                         status = "AGENT_LOGGEDOFF";
1623                 }
1624
1625                 if (owner) {
1626                         ast_channel_unlock(owner);
1627                         owner = ast_channel_unref(owner);
1628                 }
1629
1630                 astman_append(s, "Event: Agents\r\n"
1631                         "Agent: %s\r\n"
1632                         "Name: %s\r\n"
1633                         "Status: %s\r\n"
1634                         "LoggedInChan: %s\r\n"
1635                         "LoggedInTime: %d\r\n"
1636                         "TalkingTo: %s\r\n"
1637                         "TalkingToChan: %s\r\n"
1638                         "%s"
1639                         "\r\n",
1640                         p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1641                 ast_mutex_unlock(&p->lock);
1642         }
1643         AST_LIST_UNLOCK(&agents);
1644         astman_append(s, "Event: AgentsComplete\r\n"
1645                 "%s"
1646                 "\r\n",idText);
1647         return 0;
1648 }
1649
1650 static int agent_logoff(const char *agent, int soft)
1651 {
1652         struct agent_pvt *p;
1653         int ret = -1; /* Return -1 if no agent if found */
1654
1655         AST_LIST_LOCK(&agents);
1656         AST_LIST_TRAVERSE(&agents, p, list) {
1657                 if (!strcasecmp(p->agent, agent)) {
1658                         ret = 0;
1659                         if (p->owner || p->chan) {
1660                                 if (!soft) {
1661                                         struct ast_channel *owner;
1662                                         ast_mutex_lock(&p->lock);
1663                                         owner = agent_lock_owner(p);
1664
1665                                         if (owner) {
1666                                                 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
1667                                                 ast_channel_unlock(owner);
1668                                                 owner = ast_channel_unref(owner);
1669                                         }
1670
1671                                         while (p->chan && ast_channel_trylock(p->chan)) {
1672                                                 DEADLOCK_AVOIDANCE(&p->lock);
1673                                         }
1674                                         if (p->chan) {
1675                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1676                                                 ast_channel_unlock(p->chan);
1677                                         }
1678
1679                                         ast_mutex_unlock(&p->lock);
1680                                 } else
1681                                         p->deferlogoff = 1;
1682                         }
1683                         break;
1684                 }
1685         }
1686         AST_LIST_UNLOCK(&agents);
1687
1688         return ret;
1689 }
1690
1691 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1692 {
1693         int ret;
1694         const char *agent;
1695
1696         switch (cmd) {
1697         case CLI_INIT:
1698                 e->command = "agent logoff";
1699                 e->usage =
1700                         "Usage: agent logoff <channel> [soft]\n"
1701                         "       Sets an agent as no longer logged in.\n"
1702                         "       If 'soft' is specified, do not hangup existing calls.\n";
1703                 return NULL;
1704         case CLI_GENERATE:
1705                 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
1706         }
1707
1708         if (a->argc < 3 || a->argc > 4)
1709                 return CLI_SHOWUSAGE;
1710         if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
1711                 return CLI_SHOWUSAGE;
1712
1713         agent = a->argv[2] + 6;
1714         ret = agent_logoff(agent, a->argc == 4);
1715         if (ret == 0)
1716                 ast_cli(a->fd, "Logging out %s\n", agent);
1717
1718         return CLI_SUCCESS;
1719 }
1720
1721 /*!
1722  * Sets an agent as no longer logged in in the Manager API.
1723  * It is registered on load_module() and it gets called by the manager backend.
1724  * \param s
1725  * \param m
1726  * \returns 
1727  * \sa action_agents(), load_module().
1728  */
1729 static int action_agent_logoff(struct mansession *s, const struct message *m)
1730 {
1731         const char *agent = astman_get_header(m, "Agent");
1732         const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1733         int soft;
1734         int ret; /* return value of agent_logoff */
1735
1736         if (ast_strlen_zero(agent)) {
1737                 astman_send_error(s, m, "No agent specified");
1738                 return 0;
1739         }
1740
1741         soft = ast_true(soft_s) ? 1 : 0;
1742         ret = agent_logoff(agent, soft);
1743         if (ret == 0)
1744                 astman_send_ack(s, m, "Agent logged out");
1745         else
1746                 astman_send_error(s, m, "No such agent");
1747
1748         return 0;
1749 }
1750
1751 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1752 {
1753         char *ret = NULL;
1754
1755         if (pos == 2) {
1756                 struct agent_pvt *p;
1757                 char name[AST_MAX_AGENT];
1758                 int which = 0, len = strlen(word);
1759
1760                 AST_LIST_LOCK(&agents);
1761                 AST_LIST_TRAVERSE(&agents, p, list) {
1762                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1763                         if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
1764                                 ret = ast_strdup(name);
1765                                 break;
1766                         }
1767                 }
1768                 AST_LIST_UNLOCK(&agents);
1769         } else if (pos == 3 && state == 0) 
1770                 return ast_strdup("soft");
1771         
1772         return ret;
1773 }
1774
1775 /*!
1776  * Show agents in cli.
1777  */
1778 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1779 {
1780         struct agent_pvt *p;
1781         char username[AST_MAX_BUF];
1782         char location[AST_MAX_BUF] = "";
1783         char talkingto[AST_MAX_BUF] = "";
1784         char music[AST_MAX_BUF];
1785         int count_agents = 0;           /*!< Number of agents configured */
1786         int online_agents = 0;          /*!< Number of online agents */
1787         int offline_agents = 0;         /*!< Number of offline agents */
1788
1789         switch (cmd) {
1790         case CLI_INIT:
1791                 e->command = "agent show";
1792                 e->usage =
1793                         "Usage: agent show\n"
1794                         "       Provides summary information on agents.\n";
1795                 return NULL;
1796         case CLI_GENERATE:
1797                 return NULL;
1798         }
1799
1800         if (a->argc != 2)
1801                 return CLI_SHOWUSAGE;
1802
1803         AST_LIST_LOCK(&agents);
1804         AST_LIST_TRAVERSE(&agents, p, list) {
1805                 struct ast_channel *owner;
1806                 ast_mutex_lock(&p->lock);
1807                 owner = agent_lock_owner(p);
1808                 if (p->pending) {
1809                         if (p->group)
1810                                 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
1811                         else
1812                                 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
1813                 } else {
1814                         if (!ast_strlen_zero(p->name))
1815                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1816                         else
1817                                 username[0] = '\0';
1818                         if (p->chan) {
1819                                 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1820                                 if (owner && ast_bridged_channel(owner)) {
1821                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1822                                 } else {
1823                                         strcpy(talkingto, " is idle");
1824                                 }
1825                                 online_agents++;
1826                         } else {
1827                                 strcpy(location, "not logged in");
1828                                 talkingto[0] = '\0';
1829                                 offline_agents++;
1830                         }
1831                         if (!ast_strlen_zero(p->moh))
1832                                 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1833                         ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
1834                                 username, location, talkingto, music);
1835                         count_agents++;
1836                 }
1837
1838                 if (owner) {
1839                         ast_channel_unlock(owner);
1840                         owner = ast_channel_unref(owner);
1841                 }
1842                 ast_mutex_unlock(&p->lock);
1843         }
1844         AST_LIST_UNLOCK(&agents);
1845         if ( !count_agents ) 
1846                 ast_cli(a->fd, "No Agents are configured in %s\n",config);
1847         else 
1848                 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1849         ast_cli(a->fd, "\n");
1850                         
1851         return CLI_SUCCESS;
1852 }
1853
1854
1855 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1856 {
1857         struct agent_pvt *p;
1858         char username[AST_MAX_BUF];
1859         char location[AST_MAX_BUF] = "";
1860         char talkingto[AST_MAX_BUF] = "";
1861         char music[AST_MAX_BUF];
1862         int count_agents = 0;           /* Number of agents configured */
1863         int online_agents = 0;          /* Number of online agents */
1864         int agent_status = 0;           /* 0 means offline, 1 means online */
1865
1866         switch (cmd) {
1867         case CLI_INIT:
1868                 e->command = "agent show online";
1869                 e->usage =
1870                         "Usage: agent show online\n"
1871                         "       Provides a list of all online agents.\n";
1872                 return NULL;
1873         case CLI_GENERATE:
1874                 return NULL;
1875         }
1876
1877         if (a->argc != 3)
1878                 return CLI_SHOWUSAGE;
1879
1880         AST_LIST_LOCK(&agents);
1881         AST_LIST_TRAVERSE(&agents, p, list) {
1882                 struct ast_channel *owner;
1883
1884                 agent_status = 0;       /* reset it to offline */
1885                 ast_mutex_lock(&p->lock);
1886                 owner = agent_lock_owner(p);
1887
1888                 if (!ast_strlen_zero(p->name))
1889                         snprintf(username, sizeof(username), "(%s) ", p->name);
1890                 else
1891                         username[0] = '\0';
1892                 if (p->chan) {
1893                         snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1894                         if (p->owner && ast_bridged_channel(p->owner)) {
1895                                 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1896                         } else {
1897                                 strcpy(talkingto, " is idle");
1898                         }
1899                         agent_status = 1;
1900                         online_agents++;
1901                 }
1902
1903                 if (owner) {
1904                         ast_channel_unlock(owner);
1905                         owner = ast_channel_unref(owner);
1906                 }
1907
1908                 if (!ast_strlen_zero(p->moh))
1909                         snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1910                 if (agent_status)
1911                         ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
1912                 count_agents++;
1913                 ast_mutex_unlock(&p->lock);
1914         }
1915         AST_LIST_UNLOCK(&agents);
1916         if (!count_agents) 
1917                 ast_cli(a->fd, "No Agents are configured in %s\n", config);
1918         else
1919                 ast_cli(a->fd, "%d agents online\n", online_agents);
1920         ast_cli(a->fd, "\n");
1921         return CLI_SUCCESS;
1922 }
1923
1924 static const char agent_logoff_usage[] =
1925 "Usage: agent logoff <channel> [soft]\n"
1926 "       Sets an agent as no longer logged in.\n"
1927 "       If 'soft' is specified, do not hangup existing calls.\n";
1928
1929 static struct ast_cli_entry cli_agents[] = {
1930         AST_CLI_DEFINE(agents_show, "Show status of agents"),
1931         AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
1932         AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
1933 };
1934
1935 /*!
1936  * Called by the AgentLogin application (from the dial plan).
1937  * 
1938  * \brief Log in agent application.
1939  *
1940  * \param chan
1941  * \param data
1942  * \returns
1943  * \sa agentmonitoroutgoing_exec(), load_module().
1944  */
1945 static int login_exec(struct ast_channel *chan, const char *data)
1946 {
1947         int res=0;
1948         int tries = 0;
1949         int max_login_tries = maxlogintries;
1950         struct agent_pvt *p;
1951         struct ast_module_user *u;
1952         char user[AST_MAX_AGENT] = "";
1953         char pass[AST_MAX_AGENT];
1954         char agent[AST_MAX_AGENT] = "";
1955         char xpass[AST_MAX_AGENT] = "";
1956         char *errmsg;
1957         char *parse;
1958         AST_DECLARE_APP_ARGS(args,
1959                              AST_APP_ARG(agent_id);
1960                              AST_APP_ARG(options);
1961                              AST_APP_ARG(extension);
1962                 );
1963         const char *tmpoptions = NULL;
1964         int play_announcement = 1;
1965         char agent_goodbye[AST_MAX_FILENAME_LEN];
1966         int update_cdr = updatecdr;
1967         char *filename = "agent-loginok";
1968
1969         u = ast_module_user_add(chan);
1970
1971         parse = ast_strdupa(data);
1972
1973         AST_STANDARD_APP_ARGS(args, parse);
1974
1975         ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1976
1977         ast_channel_lock(chan);
1978         /* Set Channel Specific Login Overrides */
1979         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1980                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1981                 if (max_login_tries < 0)
1982                         max_login_tries = 0;
1983                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1984                 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));
1985         }
1986         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1987                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1988                         update_cdr = 1;
1989                 else
1990                         update_cdr = 0;
1991                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1992                 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,ast_channel_name(chan));
1993         }
1994         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1995                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1996                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1997                 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,ast_channel_name(chan));
1998         }
1999         ast_channel_unlock(chan);
2000         /* End Channel Specific Login Overrides */
2001         
2002         if (!ast_strlen_zero(args.options)) {
2003                 if (strchr(args.options, 's')) {
2004                         play_announcement = 0;
2005                 }
2006         }
2007
2008         if (ast_channel_state(chan) != AST_STATE_UP)
2009                 res = ast_answer(chan);
2010         if (!res) {
2011                 if (!ast_strlen_zero(args.agent_id))
2012                         ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
2013                 else
2014                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
2015         }
2016         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
2017                 tries++;
2018                 /* Check for password */
2019                 AST_LIST_LOCK(&agents);
2020                 AST_LIST_TRAVERSE(&agents, p, list) {
2021                         if (!strcmp(p->agent, user) && !p->pending)
2022                                 ast_copy_string(xpass, p->password, sizeof(xpass));
2023                 }
2024                 AST_LIST_UNLOCK(&agents);
2025                 if (!res) {
2026                         if (!ast_strlen_zero(xpass))
2027                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
2028                         else
2029                                 pass[0] = '\0';
2030                 }
2031                 errmsg = "agent-incorrect";
2032
2033 #if 0
2034                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
2035 #endif          
2036
2037                 /* Check again for accuracy */
2038                 AST_LIST_LOCK(&agents);
2039                 AST_LIST_TRAVERSE(&agents, p, list) {
2040                         int unlock_channel = 1;
2041                         ast_channel_lock(chan);
2042                         ast_mutex_lock(&p->lock);
2043                         if (!strcmp(p->agent, user) &&
2044                             !strcmp(p->password, pass) && !p->pending) {
2045
2046                                 /* Ensure we can't be gotten until we're done */
2047                                 p->lastdisc = ast_tvnow();
2048                                 p->lastdisc.tv_sec++;
2049
2050                                 /* Set Channel Specific Agent Overrides */
2051                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2052                                         if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2053                                                 p->ackcall = 1;
2054                                         } else {
2055                                                 p->ackcall = 0;
2056                                         }
2057                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2058                                         ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
2059                                         ast_set_flag(p, AGENT_FLAG_ACKCALL);
2060                                 } else {
2061                                         p->ackcall = ackcall;
2062                                 }
2063                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
2064                                         p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
2065                                         if (p->autologoff < 0)
2066                                                 p->autologoff = 0;
2067                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2068                                         ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
2069                                         ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
2070                                 } else {
2071                                         p->autologoff = autologoff;
2072                                 }
2073                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
2074                                         p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
2075                                         if (p->wrapuptime < 0)
2076                                                 p->wrapuptime = 0;
2077                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2078                                         ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
2079                                         ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
2080                                 } else {
2081                                         p->wrapuptime = wrapuptime;
2082                                 }
2083                                 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2084                                 if (!ast_strlen_zero(tmpoptions)) {
2085                                         p->acceptdtmf = *tmpoptions;
2086                                         ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
2087                                         ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
2088                                 }
2089                                 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
2090                                 if (!ast_strlen_zero(tmpoptions)) {
2091                                         p->enddtmf = *tmpoptions;
2092                                         ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
2093                                         ast_set_flag(p, AGENT_FLAG_ENDDTMF);
2094                                 }
2095                                 ast_channel_unlock(chan);
2096                                 unlock_channel = 0;
2097                                 /* End Channel Specific Agent Overrides */
2098                                 if (!p->chan) {
2099                                         long logintime;
2100                                         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
2101
2102                                         p->logincallerid[0] = '\0';
2103                                         p->acknowledged = 0;
2104                                         
2105                                         ast_mutex_unlock(&p->lock);
2106                                         AST_LIST_UNLOCK(&agents);
2107                                         if( !res && play_announcement==1 )
2108                                                 res = ast_streamfile(chan, filename, ast_channel_language(chan));
2109                                         if (!res)
2110                                                 ast_waitstream(chan, "");
2111                                         AST_LIST_LOCK(&agents);
2112                                         ast_mutex_lock(&p->lock);
2113                                         if (!res) {
2114                                                 struct ast_format tmpfmt;
2115                                                 res = ast_set_read_format_from_cap(chan, ast_channel_nativeformats(chan));
2116                                                 if (res) {
2117                                                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
2118                                                 }
2119                                         }
2120                                         if (!res) {
2121                                                 struct ast_format tmpfmt;
2122                                                 res = ast_set_write_format_from_cap(chan, ast_channel_nativeformats(chan));
2123                                                 if (res) {
2124                                                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
2125                                                 }
2126                                         }
2127                                         /* Check once more just in case */
2128                                         if (p->chan)
2129                                                 res = -1;
2130                                         if (!res) {
2131                                                 ast_indicate_data(chan, AST_CONTROL_HOLD, 
2132                                                         S_OR(p->moh, NULL), 
2133                                                         !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2134                                                 if (p->loginstart == 0)
2135                                                         time(&p->loginstart);
2136                                                 /*** DOCUMENTATION
2137                                                         <managerEventInstance>
2138                                                                 <synopsis>Raised when an Agent has logged in.</synopsis>
2139                                                                 <syntax>
2140                                                                         <parameter name="Agent">
2141                                                                                 <para>The name of the agent.</para>
2142                                                                         </parameter>
2143                                                                 </syntax>
2144                                                                 <see-also>
2145                                                                         <ref type="application">AgentLogin</ref>
2146                                                                         <ref type="managerEvent">Agentlogoff</ref>
2147                                                                 </see-also>
2148                                                         </managerEventInstance>
2149                                                 ***/
2150                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2151                                                               "Agent: %s\r\n"
2152                                                               "Channel: %s\r\n"
2153                                                               "Uniqueid: %s\r\n",
2154                                                               p->agent, ast_channel_name(chan), ast_channel_uniqueid(chan));
2155                                                 if (update_cdr && ast_channel_cdr(chan))
2156                                                         snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "Agent/%s", p->agent);
2157                                                 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGIN", "%s", ast_channel_name(chan));
2158                                                 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
2159                                                                     ast_getformatname(ast_channel_readformat(chan)), ast_getformatname(ast_channel_writeformat(chan)));
2160                                                 /* Login this channel and wait for it to go away */
2161                                                 p->chan = chan;
2162                                                 if (p->ackcall) {
2163                                                         check_beep(p, 0);
2164                                                 } else {
2165                                                         check_availability(p, 0);
2166                                                 }
2167                                                 ast_mutex_unlock(&p->lock);
2168                                                 AST_LIST_UNLOCK(&agents);
2169                                                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2170                                                 while (res >= 0) {
2171                                                         ast_mutex_lock(&p->lock);
2172                                                         if (p->deferlogoff && p->chan) {
2173                                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
2174                                                                 p->deferlogoff = 0;
2175                                                         }
2176                                                         if (p->chan != chan)
2177                                                                 res = -1;
2178                                                         ast_mutex_unlock(&p->lock);
2179                                                         /* Yield here so other interested threads can kick in. */
2180                                                         sched_yield();
2181                                                         if (res)
2182                                                                 break;
2183
2184                                                         AST_LIST_LOCK(&agents);
2185                                                         ast_mutex_lock(&p->lock);
2186                                                         if (p->lastdisc.tv_sec) {
2187                                                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
2188                                                                         ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
2189                                                                         p->lastdisc = ast_tv(0, 0);
2190                                                                         ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2191                                                                         if (p->ackcall) {
2192                                                                                 check_beep(p, 0);
2193                                                                         } else {
2194                                                                                 check_availability(p, 0);
2195                                                                         }
2196                                                                 }
2197                                                         }
2198                                                         ast_mutex_unlock(&p->lock);
2199                                                         AST_LIST_UNLOCK(&agents);
2200
2201                                                         /*      Synchronize channel ownership between call to agent and itself. */
2202                                                         ast_mutex_lock(&p->lock);
2203                                                         if (p->app_lock_flag == 1) {
2204                                                                 ast_cond_signal(&p->login_wait_cond);
2205                                                                 ast_cond_wait(&p->app_complete_cond, &p->lock);
2206                                                         }
2207                                                         ast_mutex_unlock(&p->lock);
2208                                                         if (p->ackcall) {
2209                                                                 res = agent_ack_sleep(p);
2210                                                         } else {
2211                                                                 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2212                                                         }
2213                                                         if (p->ackcall && (res == 1)) {
2214                                                                 AST_LIST_LOCK(&agents);
2215                                                                 ast_mutex_lock(&p->lock);
2216                                                                 check_availability(p, 0);
2217                                                                 ast_mutex_unlock(&p->lock);
2218                                                                 AST_LIST_UNLOCK(&agents);
2219                                                                 res = 0;
2220                                                         }
2221                                                         sched_yield();
2222                                                 }
2223                                                 ast_mutex_lock(&p->lock);
2224                                                 /* Log us off if appropriate */
2225                                                 if (p->chan == chan) {
2226                                                         p->chan = NULL;
2227                                                 }
2228
2229                                                 /* Synchronize channel ownership between call to agent and itself. */
2230                                                 if (p->app_lock_flag == 1) {
2231                                                         ast_cond_signal(&p->login_wait_cond);
2232                                                         ast_cond_wait(&p->app_complete_cond, &p->lock);
2233                                                 }
2234
2235                                                 if (res && p->owner)
2236                                                         ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
2237
2238                                                 p->acknowledged = 0;
2239                                                 logintime = time(NULL) - p->loginstart;
2240                                                 p->loginstart = 0;
2241                                                 ast_mutex_unlock(&p->lock);
2242                                                 /*** DOCUMENTATION
2243                                                         <managerEventInstance>
2244                                                                 <synopsis>Raised when an Agent has logged off.</synopsis>
2245                                                                 <syntax>
2246                                                                         <xi:include xpointer="xpointer(/docs/managerEvent[@name='Agentlogin']/managerEventInstance/syntax/parameter[@name='Agent'])" />
2247                                                                 </syntax>
2248                                                                 <see-also>
2249                                                                         <ref type="managerEvent">Agentlogin</ref>
2250                                                                 </see-also>
2251                                                         </managerEventInstance>
2252                                                 ***/
2253                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2254                                                               "Agent: %s\r\n"
2255                                                               "Logintime: %ld\r\n"
2256                                                               "Uniqueid: %s\r\n",
2257                                                               p->agent, logintime, ast_channel_uniqueid(chan));
2258                                                 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGOFF", "%s|%ld", ast_channel_name(chan), logintime);
2259                                                 ast_verb(2, "Agent '%s' logged out\n", p->agent);
2260                                                 /* If there is no owner, go ahead and kill it now */
2261                                                 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
2262                                                 if (p->dead && !p->owner) {
2263                                                         ast_mutex_destroy(&p->lock);
2264                                                         ast_cond_destroy(&p->app_complete_cond);
2265                                                         ast_cond_destroy(&p->login_wait_cond);
2266                                                         ast_free(p);
2267                                                 }
2268                                         }
2269                                         else {
2270                                                 ast_mutex_unlock(&p->lock);
2271                                                 p = NULL;
2272                                         }
2273                                         res = -1;
2274                                 } else {
2275                                         ast_mutex_unlock(&p->lock);
2276                                         errmsg = "agent-alreadyon";
2277                                         p = NULL;
2278                                 }
2279                                 break;
2280                         }
2281                         ast_mutex_unlock(&p->lock);
2282                         if (unlock_channel) {
2283                                 ast_channel_unlock(chan);
2284                         }
2285                 }
2286                 if (!p)
2287                         AST_LIST_UNLOCK(&agents);
2288
2289                 if (!res && (max_login_tries==0 || tries < max_login_tries))
2290                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2291         }
2292                 
2293         if (!res)
2294                 res = ast_safe_sleep(chan, 500);
2295
2296         ast_module_user_remove(u);
2297         
2298         return -1;
2299 }
2300
2301 /*!
2302  *  \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2303  *
2304  * \param chan
2305  * \param data
2306  * \returns
2307  * \sa login_exec(), load_module().
2308  */
2309 static int agentmonitoroutgoing_exec(struct ast_channel *chan, const char *data)
2310 {
2311         int exitifnoagentid = 0;
2312         int nowarnings = 0;
2313         int changeoutgoing = 0;
2314         int res = 0;
2315         char agent[AST_MAX_AGENT];
2316
2317         if (data) {
2318                 if (strchr(data, 'd'))
2319                         exitifnoagentid = 1;
2320                 if (strchr(data, 'n'))
2321                         nowarnings = 1;
2322                 if (strchr(data, 'c'))
2323                         changeoutgoing = 1;
2324         }
2325         if (ast_channel_caller(chan)->id.number.valid
2326                 && !ast_strlen_zero(ast_channel_caller(chan)->id.number.str)) {
2327                 const char *tmp;
2328                 char agentvar[AST_MAX_BUF];
2329                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
2330                         ast_channel_caller(chan)->id.number.str);
2331                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2332                         struct agent_pvt *p;
2333                         ast_copy_string(agent, tmp, sizeof(agent));
2334                         AST_LIST_LOCK(&agents);
2335                         AST_LIST_TRAVERSE(&agents, p, list) {
2336                                 if (!strcasecmp(p->agent, tmp)) {
2337                                         if (changeoutgoing) snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "Agent/%s", p->agent);
2338                                         __agent_start_monitoring(chan, p, 1);
2339                                         break;
2340                                 }
2341                         }
2342                         AST_LIST_UNLOCK(&agents);
2343                         
2344                 } else {
2345                         res = -1;
2346                         if (!nowarnings)
2347                                 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);
2348                 }
2349         } else {
2350                 res = -1;
2351                 if (!nowarnings)
2352                         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");
2353         }
2354         if (res) {
2355                 if (exitifnoagentid)
2356                         return res;
2357         }
2358         return 0;
2359 }
2360
2361 /*! \brief Part of PBX channel interface */
2362 static int agent_devicestate(const char *data)
2363 {
2364         struct agent_pvt *p;
2365         const char *s;
2366         ast_group_t groupmatch;
2367         int groupoff;
2368         int res = AST_DEVICE_INVALID;
2369         
2370         s = data;
2371         if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
2372                 groupmatch = (1 << groupoff);
2373         else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
2374                 groupmatch = (1 << groupoff);
2375         } else 
2376                 groupmatch = 0;
2377
2378         /* Check actual logged in agents first */
2379         AST_LIST_LOCK(&agents);
2380         AST_LIST_TRAVERSE(&agents, p, list) {
2381                 ast_mutex_lock(&p->lock);
2382                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2383                         if (p->owner) {
2384                                 if (res != AST_DEVICE_INUSE)
2385                                         res = AST_DEVICE_BUSY;
2386                         } else {
2387                                 if (res == AST_DEVICE_BUSY)
2388                                         res = AST_DEVICE_INUSE;
2389                                 if (p->chan) {
2390                                         if (res == AST_DEVICE_INVALID)
2391                                                 res = AST_DEVICE_UNKNOWN;
2392                                 } else if (res == AST_DEVICE_INVALID)   
2393                                         res = AST_DEVICE_UNAVAILABLE;
2394                         }
2395                         if (!strcmp(data, p->agent)) {
2396                                 ast_mutex_unlock(&p->lock);
2397                                 break;
2398                         }
2399                 }
2400                 ast_mutex_unlock(&p->lock);
2401         }
2402         AST_LIST_UNLOCK(&agents);
2403         return res;
2404 }
2405
2406 /*!
2407  * \note This function expects the agent list to be locked
2408  */
2409 static struct agent_pvt *find_agent(char *agentid)
2410 {
2411         struct agent_pvt *cur;
2412
2413         AST_LIST_TRAVERSE(&agents, cur, list) {
2414                 if (!strcmp(cur->agent, agentid))
2415                         break;  
2416         }
2417
2418         return cur;     
2419 }
2420
2421 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2422 {
2423         char *parse;    
2424         AST_DECLARE_APP_ARGS(args,
2425                 AST_APP_ARG(agentid);
2426                 AST_APP_ARG(item);
2427         );
2428         char *tmp;
2429         struct agent_pvt *agent;
2430
2431         buf[0] = '\0';
2432
2433         if (ast_strlen_zero(data)) {
2434                 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2435                 return -1;
2436         }
2437
2438         parse = ast_strdupa(data);
2439
2440         AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2441         if (!args.item)
2442                 args.item = "status";
2443
2444         AST_LIST_LOCK(&agents);
2445
2446         if (!(agent = find_agent(args.agentid))) {
2447                 AST_LIST_UNLOCK(&agents);
2448                 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2449                 return -1;
2450         }
2451
2452         if (!strcasecmp(args.item, "status")) {
2453                 char *status = "LOGGEDOUT";
2454                 if (agent->chan) {
2455                         status = "LOGGEDIN";
2456                 }
2457                 ast_copy_string(buf, status, len);
2458         } else if (!strcasecmp(args.item, "password")) 
2459                 ast_copy_string(buf, agent->password, len);
2460         else if (!strcasecmp(args.item, "name"))
2461                 ast_copy_string(buf, agent->name, len);
2462         else if (!strcasecmp(args.item, "mohclass"))
2463                 ast_copy_string(buf, agent->moh, len);
2464         else if (!strcasecmp(args.item, "channel")) {
2465                 if (agent->chan) {
2466                         ast_channel_lock(agent->chan);
2467                         ast_copy_string(buf, ast_channel_name(agent->chan), len);
2468                         ast_channel_unlock(agent->chan);
2469                         tmp = strrchr(buf, '-');
2470                         if (tmp)
2471                                 *tmp = '\0';
2472                 } 
2473         } else if (!strcasecmp(args.item, "fullchannel")) {
2474                 if (agent->chan) {
2475                         ast_channel_lock(agent->chan);
2476                         ast_copy_string(buf, ast_channel_name(agent->chan), len);
2477                         ast_channel_unlock(agent->chan);
2478                 } 
2479         } else if (!strcasecmp(args.item, "exten")) {
2480                 buf[0] = '\0';
2481         }
2482
2483         AST_LIST_UNLOCK(&agents);
2484
2485         return 0;
2486 }
2487
2488 static struct ast_custom_function agent_function = {
2489         .name = "AGENT",
2490         .read = function_agent,
2491 };
2492
2493 /*!
2494  * \internal
2495  * \brief Callback used to generate the agents tree.
2496  * \param[in] search The search pattern tree.
2497  * \retval NULL on error.
2498  * \retval non-NULL The generated tree.
2499  */
2500 static int agents_data_provider_get(const struct ast_data_search *search,
2501         struct ast_data *data_root)
2502 {
2503         struct agent_pvt *p;
2504         struct ast_data *data_agent, *data_channel, *data_talkingto;
2505
2506         AST_LIST_LOCK(&agents);
2507         AST_LIST_TRAVERSE(&agents, p, list) {
2508                 struct ast_channel *owner;
2509
2510                 data_agent = ast_data_add_node(data_root, "agent");
2511                 if (!data_agent) {
2512                         continue;
2513                 }
2514
2515                 ast_mutex_lock(&p->lock);
2516                 owner = agent_lock_owner(p);
2517
2518                 if (!(p->pending)) {
2519                         ast_data_add_str(data_agent, "id", p->agent);
2520                         ast_data_add_structure(agent_pvt, data_agent, p);
2521
2522                         ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
2523                         if (p->chan) {
2524                                 data_channel = ast_data_add_node(data_agent, "loggedon");
2525                                 if (!data_channel) {
2526                                         ast_mutex_unlock(&p->lock);
2527                                         ast_data_remove_node(data_root, data_agent);
2528                                         if (owner) {
2529                                                 ast_channel_unlock(owner);
2530                                                 owner = ast_channel_unref(owner);
2531                                         }
2532                                         continue;
2533                                 }
2534                                 ast_channel_data_add_structure(data_channel, p->chan, 0);
2535                                 if (owner && ast_bridged_channel(owner)) {
2536                                         data_talkingto = ast_data_add_node(data_agent, "talkingto");
2537                                         if (!data_talkingto) {
2538                                                 ast_mutex_unlock(&p->lock);
2539                                                 ast_data_remove_node(data_root, data_agent);
2540                                                 if (owner) {
2541                                                         ast_channel_unlock(owner);
2542                                                         owner = ast_channel_unref(owner);
2543                                                 }
2544                                                 continue;
2545                                         }
2546                                         ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
2547                                 }
2548                         } else {
2549                                 ast_data_add_node(data_agent, "talkingto");
2550                                 ast_data_add_node(data_agent, "loggedon");
2551                         }
2552                         ast_data_add_str(data_agent, "musiconhold", p->moh);
2553                 }
2554
2555                 if (owner) {
2556                         ast_channel_unlock(owner);
2557                         owner = ast_channel_unref(owner);
2558                 }
2559
2560                 ast_mutex_unlock(&p->lock);
2561
2562                 /* if this agent doesn't match remove the added agent. */
2563                 if (!ast_data_search_match(search, data_agent)) {
2564                         ast_data_remove_node(data_root, data_agent);
2565                 }
2566         }
2567         AST_LIST_UNLOCK(&agents);
2568
2569         return 0;
2570 }
2571
2572 static const struct ast_data_handler agents_data_provider = {
2573         .version = AST_DATA_HANDLER_VERSION,
2574         .get = agents_data_provider_get
2575 };
2576
2577 static const struct ast_data_entry agents_data_providers[] = {
2578         AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
2579 };
2580
2581 /*!
2582  * \brief Initialize the Agents module.
2583  * This function is being called by Asterisk when loading the module. 
2584  * Among other things it registers applications, cli commands and reads the cofiguration file.
2585  *
2586  * \returns int Always 0.
2587  */
2588 static int load_module(void)
2589 {
2590         if (!(agent_tech.capabilities = ast_format_cap_alloc())) {
2591                 ast_log(LOG_ERROR, "ast_format_cap_alloc_nolock fail.\n");
2592                 return AST_MODULE_LOAD_FAILURE;
2593         }
2594         ast_format_cap_add_all(agent_tech.capabilities);
2595         /* Make sure we can register our agent channel type */
2596         if (ast_channel_register(&agent_tech)) {
2597                 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2598                 return AST_MODULE_LOAD_FAILURE;
2599         }
2600         /* Read in the config */
2601         if (!read_agent_config(0))
2602                 return AST_MODULE_LOAD_DECLINE;
2603         /* Dialplan applications */
2604         ast_register_application_xml(app, login_exec);
2605         ast_register_application_xml(app3, agentmonitoroutgoing_exec);
2606
2607         /* data tree */
2608         ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
2609
2610         /* Manager commands */
2611         ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
2612         ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
2613
2614         /* CLI Commands */
2615         ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
2616
2617         /* Dialplan Functions */
2618         ast_custom_function_register(&agent_function);
2619
2620         return AST_MODULE_LOAD_SUCCESS;
2621 }
2622
2623 static int reload(void)
2624 {
2625         return read_agent_config(1);
2626 }
2627
2628 static int unload_module(void)
2629 {
2630         struct agent_pvt *p;
2631         /* First, take us out of the channel loop */
2632         ast_channel_unregister(&agent_tech);
2633         /* Unregister dialplan functions */
2634         ast_custom_function_unregister(&agent_function);        
2635         /* Unregister CLI commands */
2636         ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
2637         /* Unregister dialplan applications */
2638         ast_unregister_application(app);
2639         ast_unregister_application(app3);
2640         /* Unregister manager command */
2641         ast_manager_unregister("Agents");
2642         ast_manager_unregister("AgentLogoff");
2643         /* Unregister the data tree */
2644         ast_data_unregister(NULL);
2645         /* Unregister channel */
2646         AST_LIST_LOCK(&agents);
2647         /* Hangup all interfaces if they have an owner */
2648         while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2649                 if (p->owner)
2650                         ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2651                 ast_free(p);
2652         }
2653         AST_LIST_UNLOCK(&agents);
2654
2655         agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2656         return 0;
2657 }
2658
2659 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Agent Proxy Channel",
2660                 .load = load_module,
2661                 .unload = unload_module,
2662                 .reload = reload,
2663                 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2664                 .nonoptreq = "res_monitor,chan_local",
2665                );