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