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