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