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