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