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