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