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