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