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