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