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