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