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