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