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