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