Fudges for wav16, just like wav49
[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 base[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(base, p->chan->name, sizeof(base));
301                         if ((tmp = strrchr(base, '-'))) {
302                                 *tmp = '\0';
303                         }
304                         if (strcasecmp(p->chan->name, device) == 0 || strcasecmp(base, 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 && !ast_check_hangup(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         } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1123                 ast_log(LOG_ERROR, "%s contains a parsing error.  Aborting\n", config);
1124                 return 0;
1125         }
1126         if ((ucfg = ast_config_load("users.conf", config_flags))) {
1127                 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
1128                         ucfg = NULL;
1129                 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
1130                         ast_log(LOG_ERROR, "users.conf contains a parsing error.  Aborting\n");
1131                         return 0;
1132                 }
1133         }
1134
1135         AST_LIST_LOCK(&agents);
1136         AST_LIST_TRAVERSE(&agents, p, list) {
1137                 p->dead = 1;
1138         }
1139         strcpy(moh, "default");
1140         /* set the default recording values */
1141         recordagentcalls = 0;
1142         strcpy(recordformat, "wav");
1143         strcpy(recordformatext, "wav");
1144         urlprefix[0] = '\0';
1145         savecallsin[0] = '\0';
1146
1147         /* Read in [general] section for persistence */
1148         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1149                 persistent_agents = ast_true(general_val);
1150         multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1151
1152         /* Read in the [agents] section */
1153         v = ast_variable_browse(cfg, "agents");
1154         while(v) {
1155                 /* Create the interface list */
1156                 if (!strcasecmp(v->name, "agent")) {
1157                         add_agent(v->value, 0);
1158                 } else if (!strcasecmp(v->name, "group")) {
1159                         group = ast_get_group(v->value);
1160                 } else if (!strcasecmp(v->name, "autologoff")) {
1161                         autologoff = atoi(v->value);
1162                         if (autologoff < 0)
1163                                 autologoff = 0;
1164                 } else if (!strcasecmp(v->name, "ackcall")) {
1165                         if (!strcasecmp(v->value, "always"))
1166                                 ackcall = 2;
1167                         else if (ast_true(v->value))
1168                                 ackcall = 1;
1169                         else
1170                                 ackcall = 0;
1171                 } else if (!strcasecmp(v->name, "endcall")) {
1172                         endcall = ast_true(v->value);
1173                 } else if (!strcasecmp(v->name, "acceptdtmf")) {
1174                         acceptdtmf = *(v->value);
1175                         ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
1176                 } else if (!strcasecmp(v->name, "enddtmf")) {
1177                         enddtmf = *(v->value);
1178                 } else if (!strcasecmp(v->name, "wrapuptime")) {
1179                         wrapuptime = atoi(v->value);
1180                         if (wrapuptime < 0)
1181                                 wrapuptime = 0;
1182                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1183                         maxlogintries = atoi(v->value);
1184                         if (maxlogintries < 0)
1185                                 maxlogintries = 0;
1186                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1187                         strcpy(agentgoodbye,v->value);
1188                 } else if (!strcasecmp(v->name, "musiconhold")) {
1189                         ast_copy_string(moh, v->value, sizeof(moh));
1190                 } else if (!strcasecmp(v->name, "updatecdr")) {
1191                         if (ast_true(v->value))
1192                                 updatecdr = 1;
1193                         else
1194                                 updatecdr = 0;
1195                 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1196                         if (ast_true(v->value))
1197                                 autologoffunavail = 1;
1198                         else
1199                                 autologoffunavail = 0;
1200                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1201                         recordagentcalls = ast_true(v->value);
1202                 } else if (!strcasecmp(v->name, "recordformat")) {
1203                         ast_copy_string(recordformat, v->value, sizeof(recordformat));
1204                         if (!strcasecmp(v->value, "wav49")) {
1205                                 strcpy(recordformatext, "WAV");
1206                         } else if (!strcasecmp(v->value, "wav16")) {
1207                                 strcpy(recordformatext, "Wav");
1208                         } else {
1209                                 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1210                         }
1211                 } else if (!strcasecmp(v->name, "urlprefix")) {
1212                         ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1213                         if (urlprefix[strlen(urlprefix) - 1] != '/')
1214                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1215                 } else if (!strcasecmp(v->name, "savecallsin")) {
1216                         if (v->value[0] == '/')
1217                                 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1218                         else
1219                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1220                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1221                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1222                 } else if (!strcasecmp(v->name, "custom_beep")) {
1223                         ast_copy_string(beep, v->value, sizeof(beep));
1224                 }
1225                 v = v->next;
1226         }
1227         if (ucfg) {
1228                 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1229                 catname = ast_category_browse(ucfg, NULL);
1230                 while(catname) {
1231                         if (strcasecmp(catname, "general")) {
1232                                 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1233                                 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1234                                         char tmp[256];
1235                                         const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1236                                         const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1237                                         if (!fullname)
1238                                                 fullname = "";
1239                                         if (!secret)
1240                                                 secret = "";
1241                                         snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1242                                         add_agent(tmp, 0);
1243                                 }
1244                         }
1245                         catname = ast_category_browse(ucfg, catname);
1246                 }
1247                 ast_config_destroy(ucfg);
1248         }
1249         AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1250                 if (p->dead) {
1251                         AST_LIST_REMOVE_CURRENT(list);
1252                         /* Destroy if  appropriate */
1253                         if (!p->owner) {
1254                                 if (!p->chan) {
1255                                         ast_mutex_destroy(&p->lock);
1256                                         ast_mutex_destroy(&p->app_lock);
1257                                         ast_free(p);
1258                                 } else {
1259                                         /* Cause them to hang up */
1260                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1261                                 }
1262                         }
1263                 }
1264         }
1265         AST_LIST_TRAVERSE_SAFE_END;
1266         AST_LIST_UNLOCK(&agents);
1267         ast_config_destroy(cfg);
1268         return 1;
1269 }
1270
1271 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1272 {
1273         struct ast_channel *chan=NULL, *parent=NULL;
1274         struct agent_pvt *p;
1275         int res;
1276
1277         ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
1278         if (needlock)
1279                 AST_LIST_LOCK(&agents);
1280         AST_LIST_TRAVERSE(&agents, p, list) {
1281                 if (p == newlyavailable) {
1282                         continue;
1283                 }
1284                 ast_mutex_lock(&p->lock);
1285                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1286                         ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1287                         /* We found a pending call, time to merge */
1288                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
1289                         parent = p->owner;
1290                         p->abouttograb = 1;
1291                         ast_mutex_unlock(&p->lock);
1292                         break;
1293                 }
1294                 ast_mutex_unlock(&p->lock);
1295         }
1296         if (needlock)
1297                 AST_LIST_UNLOCK(&agents);
1298         if (parent && chan)  {
1299                 if (newlyavailable->ackcall > 1) {
1300                         /* Don't do beep here */
1301                         res = 0;
1302                 } else {
1303                         ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1304                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1305                         ast_debug(3, "Played beep, result '%d'\n", res);
1306                         if (!res) {
1307                                 res = ast_waitstream(newlyavailable->chan, "");
1308                                 ast_debug(1, "Waited for stream, result '%d'\n", res);
1309                         }
1310                 }
1311                 if (!res) {
1312                         /* Note -- parent may have disappeared */
1313                         if (p->abouttograb) {
1314                                 newlyavailable->acknowledged = 1;
1315                                 /* Safe -- agent lock already held */
1316                                 ast_setstate(parent, AST_STATE_UP);
1317                                 ast_setstate(chan, AST_STATE_UP);
1318                                 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1319                                 /* Go ahead and mark the channel as a zombie so that masquerade will
1320                                    destroy it for us, and we need not call ast_hangup */
1321                                 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1322                                 ast_channel_masquerade(parent, chan);
1323                                 p->abouttograb = 0;
1324                         } else {
1325                                 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1326                                 agent_cleanup(newlyavailable);
1327                         }
1328                 } else {
1329                         ast_debug(1, "Ugh...  Agent hung up at exactly the wrong time\n");
1330                         agent_cleanup(newlyavailable);
1331                 }
1332         }
1333         return 0;
1334 }
1335
1336 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1337 {
1338         struct agent_pvt *p;
1339         int res=0;
1340
1341         ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1342         if (needlock)
1343                 AST_LIST_LOCK(&agents);
1344         AST_LIST_TRAVERSE(&agents, p, list) {
1345                 if (p == newlyavailable) {
1346                         continue;
1347                 }
1348                 ast_mutex_lock(&p->lock);
1349                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1350                         ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1351                         ast_mutex_unlock(&p->lock);
1352                         break;
1353                 }
1354                 ast_mutex_unlock(&p->lock);
1355         }
1356         if (needlock)
1357                 AST_LIST_UNLOCK(&agents);
1358         if (p) {
1359                 ast_mutex_unlock(&newlyavailable->lock);
1360                 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1361                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1362                 ast_debug(1, "Played beep, result '%d'\n", res);
1363                 if (!res) {
1364                         res = ast_waitstream(newlyavailable->chan, "");
1365                         ast_debug(1, "Waited for stream, result '%d'\n", res);
1366                 }
1367                 ast_mutex_lock(&newlyavailable->lock);
1368         }
1369         return res;
1370 }
1371
1372 /*! \brief Part of the Asterisk PBX interface */
1373 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1374 {
1375         struct agent_pvt *p;
1376         struct ast_channel *chan = NULL;
1377         char *s;
1378         ast_group_t groupmatch;
1379         int groupoff;
1380         int waitforagent=0;
1381         int hasagent = 0;
1382         struct timeval now;
1383
1384         s = data;
1385         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1386                 groupmatch = (1 << groupoff);
1387         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1388                 groupmatch = (1 << groupoff);
1389                 waitforagent = 1;
1390         } else 
1391                 groupmatch = 0;
1392
1393         /* Check actual logged in agents first */
1394         AST_LIST_LOCK(&agents);
1395         AST_LIST_TRAVERSE(&agents, p, list) {
1396                 ast_mutex_lock(&p->lock);
1397                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1398                     ast_strlen_zero(p->loginchan)) {
1399                         if (p->chan)
1400                                 hasagent++;
1401                         now = ast_tvnow();
1402                         if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1403                                 p->lastdisc = ast_tv(0, 0);
1404                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1405                                 if (!p->owner && p->chan) {
1406                                         /* Fixed agent */
1407                                         chan = agent_new(p, AST_STATE_DOWN);
1408                                 }
1409                                 if (chan) {
1410                                         ast_mutex_unlock(&p->lock);
1411                                         break;
1412                                 }
1413                         }
1414                 }
1415                 ast_mutex_unlock(&p->lock);
1416         }
1417         if (!p) {
1418                 AST_LIST_TRAVERSE(&agents, p, list) {
1419                         ast_mutex_lock(&p->lock);
1420                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1421                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1422                                         hasagent++;
1423                                 now = ast_tvnow();
1424 #if 0
1425                                 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", now.tv_sec, p->lastdisc.tv_sec);
1426 #endif
1427                                 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1428                                         p->lastdisc = ast_tv(0, 0);
1429                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1430                                         if (!p->owner && p->chan) {
1431                                                 /* Could still get a fixed agent */
1432                                                 chan = agent_new(p, AST_STATE_DOWN);
1433                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1434                                                 /* Adjustable agent */
1435                                                 p->chan = ast_request("Local", format, p->loginchan, cause);
1436                                                 if (p->chan)
1437                                                         chan = agent_new(p, AST_STATE_DOWN);
1438                                         }
1439                                         if (chan) {
1440                                                 ast_mutex_unlock(&p->lock);
1441                                                 break;
1442                                         }
1443                                 }
1444                         }
1445                         ast_mutex_unlock(&p->lock);
1446                 }
1447         }
1448
1449         if (!chan && waitforagent) {
1450                 /* No agent available -- but we're requesting to wait for one.
1451                    Allocate a place holder */
1452                 if (hasagent) {
1453                         ast_debug(1, "Creating place holder for '%s'\n", s);
1454                         p = add_agent(data, 1);
1455                         p->group = groupmatch;
1456                         chan = agent_new(p, AST_STATE_DOWN);
1457                         if (!chan) 
1458                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1459                 } else {
1460                         ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1461                 }
1462         }
1463         *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1464         AST_LIST_UNLOCK(&agents);
1465         return chan;
1466 }
1467
1468 static force_inline int powerof(unsigned int d)
1469 {
1470         int x = ffs(d);
1471
1472         if (x)
1473                 return x - 1;
1474
1475         return 0;
1476 }
1477
1478 /*!
1479  * Lists agents and their status to the Manager API.
1480  * It is registered on load_module() and it gets called by the manager backend.
1481  * \param s
1482  * \param m
1483  * \returns 
1484  * \sa action_agent_logoff(), load_module().
1485  */
1486 static int action_agents(struct mansession *s, const struct message *m)
1487 {
1488         const char *id = astman_get_header(m,"ActionID");
1489         char idText[256] = "";
1490         char chanbuf[256];
1491         struct agent_pvt *p;
1492         char *username = NULL;
1493         char *loginChan = NULL;
1494         char *talkingto = NULL;
1495         char *talkingtoChan = NULL;
1496         char *status = NULL;
1497
1498         if (!ast_strlen_zero(id))
1499                 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1500         astman_send_ack(s, m, "Agents will follow");
1501         AST_LIST_LOCK(&agents);
1502         AST_LIST_TRAVERSE(&agents, p, list) {
1503                 ast_mutex_lock(&p->lock);
1504
1505                 /* Status Values:
1506                    AGENT_LOGGEDOFF - Agent isn't logged in
1507                    AGENT_IDLE      - Agent is logged in, and waiting for call
1508                    AGENT_ONCALL    - Agent is logged in, and on a call
1509                    AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1510
1511                 username = S_OR(p->name, "None");
1512
1513                 /* Set a default status. It 'should' get changed. */
1514                 status = "AGENT_UNKNOWN";
1515
1516                 if (!ast_strlen_zero(p->loginchan) && !p->chan) {
1517                         loginChan = p->loginchan;
1518                         talkingto = "n/a";
1519                         talkingtoChan = "n/a";
1520                         status = "AGENT_IDLE";
1521                         if (p->acknowledged) {
1522                                 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
1523                                 loginChan = chanbuf;
1524                         }
1525                 } else if (p->chan) {
1526                         loginChan = ast_strdupa(p->chan->name);
1527                         if (p->owner && p->owner->_bridge) {
1528                                 talkingto = p->chan->cid.cid_num;
1529                                 if (ast_bridged_channel(p->owner))
1530                                         talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name);
1531                                 else
1532                                         talkingtoChan = "n/a";
1533                                 status = "AGENT_ONCALL";
1534                         } else {
1535                                 talkingto = "n/a";
1536                                 talkingtoChan = "n/a";
1537                                 status = "AGENT_IDLE";
1538                         }
1539                 } else {
1540                         loginChan = "n/a";
1541                         talkingto = "n/a";
1542                         talkingtoChan = "n/a";
1543                         status = "AGENT_LOGGEDOFF";
1544                 }
1545
1546                 astman_append(s, "Event: Agents\r\n"
1547                         "Agent: %s\r\n"
1548                         "Name: %s\r\n"
1549                         "Status: %s\r\n"
1550                         "LoggedInChan: %s\r\n"
1551                         "LoggedInTime: %d\r\n"
1552                         "TalkingTo: %s\r\n"
1553                         "TalkingToChan: %s\r\n"
1554                         "%s"
1555                         "\r\n",
1556                         p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1557                 ast_mutex_unlock(&p->lock);
1558         }
1559         AST_LIST_UNLOCK(&agents);
1560         astman_append(s, "Event: AgentsComplete\r\n"
1561                 "%s"
1562                 "\r\n",idText);
1563         return 0;
1564 }
1565
1566 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
1567 {
1568         char *tmp = NULL;
1569         char agent[AST_MAX_AGENT];
1570
1571         if (!ast_strlen_zero(logcommand))
1572                 tmp = logcommand;
1573         else
1574                 tmp = ast_strdupa("");
1575
1576         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1577
1578         if (!ast_strlen_zero(uniqueid)) {
1579                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1580                                 "Agent: %s\r\n"
1581                                 "Reason: %s\r\n"
1582                                 "Loginchan: %s\r\n"
1583                                 "Logintime: %ld\r\n"
1584                                 "Uniqueid: %s\r\n", 
1585                                 p->agent, tmp, loginchan, logintime, uniqueid);
1586         } else {
1587                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1588                                 "Agent: %s\r\n"
1589                                 "Reason: %s\r\n"
1590                                 "Loginchan: %s\r\n"
1591                                 "Logintime: %ld\r\n",
1592                                 p->agent, tmp, loginchan, logintime);
1593         }
1594
1595         ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
1596         set_agentbycallerid(p->logincallerid, NULL);
1597         p->loginchan[0] ='\0';
1598         p->logincallerid[0] = '\0';
1599         p->inherited_devicestate = -1;
1600         ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
1601         if (persistent_agents)
1602                 dump_agents();  
1603
1604 }
1605
1606 static int agent_logoff(const char *agent, int soft)
1607 {
1608         struct agent_pvt *p;
1609         long logintime;
1610         int ret = -1; /* Return -1 if no agent if found */
1611
1612         AST_LIST_LOCK(&agents);
1613         AST_LIST_TRAVERSE(&agents, p, list) {
1614                 if (!strcasecmp(p->agent, agent)) {
1615                         ret = 0;
1616                         if (p->owner || p->chan) {
1617                                 if (!soft) {
1618                                         ast_mutex_lock(&p->lock);
1619
1620                                         while (p->owner && ast_channel_trylock(p->owner)) {
1621                                                 DEADLOCK_AVOIDANCE(&p->lock);
1622                                         }
1623                                         if (p->owner) {
1624                                                 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1625                                                 ast_channel_unlock(p->owner);
1626                                         }
1627
1628                                         while (p->chan && ast_channel_trylock(p->chan)) {
1629                                                 DEADLOCK_AVOIDANCE(&p->lock);
1630                                         }
1631                                         if (p->chan) {
1632                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1633                                                 ast_channel_unlock(p->chan);
1634                                         }
1635
1636                                         ast_mutex_unlock(&p->lock);
1637                                 } else
1638                                         p->deferlogoff = 1;
1639                         } else {
1640                                 logintime = time(NULL) - p->loginstart;
1641                                 p->loginstart = 0;
1642                                 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
1643                         }
1644                         break;
1645                 }
1646         }
1647         AST_LIST_UNLOCK(&agents);
1648
1649         return ret;
1650 }
1651
1652 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1653 {
1654         int ret;
1655         char *agent;
1656
1657         switch (cmd) {
1658         case CLI_INIT:
1659                 e->command = "agent logoff";
1660                 e->usage =
1661                         "Usage: agent logoff <channel> [soft]\n"
1662                         "       Sets an agent as no longer logged in.\n"
1663                         "       If 'soft' is specified, do not hangup existing calls.\n";
1664                 return NULL;
1665         case CLI_GENERATE:
1666                 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n); 
1667         }
1668
1669         if (a->argc < 3 || a->argc > 4)
1670                 return CLI_SHOWUSAGE;
1671         if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
1672                 return CLI_SHOWUSAGE;
1673
1674         agent = a->argv[2] + 6;
1675         ret = agent_logoff(agent, a->argc == 4);
1676         if (ret == 0)
1677                 ast_cli(a->fd, "Logging out %s\n", agent);
1678
1679         return CLI_SUCCESS;
1680 }
1681
1682 /*!
1683  * Sets an agent as no longer logged in in the Manager API.
1684  * It is registered on load_module() and it gets called by the manager backend.
1685  * \param s
1686  * \param m
1687  * \returns 
1688  * \sa action_agents(), load_module().
1689  */
1690 static int action_agent_logoff(struct mansession *s, const struct message *m)
1691 {
1692         const char *agent = astman_get_header(m, "Agent");
1693         const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1694         int soft;
1695         int ret; /* return value of agent_logoff */
1696
1697         if (ast_strlen_zero(agent)) {
1698                 astman_send_error(s, m, "No agent specified");
1699                 return 0;
1700         }
1701
1702         soft = ast_true(soft_s) ? 1 : 0;
1703         ret = agent_logoff(agent, soft);
1704         if (ret == 0)
1705                 astman_send_ack(s, m, "Agent logged out");
1706         else
1707                 astman_send_error(s, m, "No such agent");
1708
1709         return 0;
1710 }
1711
1712 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1713 {
1714         char *ret = NULL;
1715
1716         if (pos == 2) {
1717                 struct agent_pvt *p;
1718                 char name[AST_MAX_AGENT];
1719                 int which = 0, len = strlen(word);
1720
1721                 AST_LIST_LOCK(&agents);
1722                 AST_LIST_TRAVERSE(&agents, p, list) {
1723                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1724                         if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
1725                                 ret = ast_strdup(name);
1726                                 break;
1727                         }
1728                 }
1729                 AST_LIST_UNLOCK(&agents);
1730         } else if (pos == 3 && state == 0) 
1731                 return ast_strdup("soft");
1732         
1733         return ret;
1734 }
1735
1736 /*!
1737  * Show agents in cli.
1738  */
1739 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1740 {
1741         struct agent_pvt *p;
1742         char username[AST_MAX_BUF];
1743         char location[AST_MAX_BUF] = "";
1744         char talkingto[AST_MAX_BUF] = "";
1745         char music[AST_MAX_BUF];
1746         int count_agents = 0;           /*!< Number of agents configured */
1747         int online_agents = 0;          /*!< Number of online agents */
1748         int offline_agents = 0;         /*!< Number of offline agents */
1749
1750         switch (cmd) {
1751         case CLI_INIT:
1752                 e->command = "agent show";
1753                 e->usage =
1754                         "Usage: agent show\n"
1755                         "       Provides summary information on agents.\n";
1756                 return NULL;
1757         case CLI_GENERATE:
1758                 return NULL;
1759         }
1760
1761         if (a->argc != 2)
1762                 return CLI_SHOWUSAGE;
1763
1764         AST_LIST_LOCK(&agents);
1765         AST_LIST_TRAVERSE(&agents, p, list) {
1766                 ast_mutex_lock(&p->lock);
1767                 if (p->pending) {
1768                         if (p->group)
1769                                 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
1770                         else
1771                                 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
1772                 } else {
1773                         if (!ast_strlen_zero(p->name))
1774                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1775                         else
1776                                 username[0] = '\0';
1777                         if (p->chan) {
1778                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1779                                 if (p->owner && ast_bridged_channel(p->owner))
1780                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1781                                  else 
1782                                         strcpy(talkingto, " is idle");
1783                                 online_agents++;
1784                         } else if (!ast_strlen_zero(p->loginchan)) {
1785                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec)) 
1786                                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1787                                 else 
1788                                         snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
1789                                 talkingto[0] = '\0';
1790                                 online_agents++;
1791                                 if (p->acknowledged)
1792                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1793                         } else {
1794                                 strcpy(location, "not logged in");
1795                                 talkingto[0] = '\0';
1796                                 offline_agents++;
1797                         }
1798                         if (!ast_strlen_zero(p->moh))
1799                                 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1800                         ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, 
1801                                 username, location, talkingto, music);
1802                         count_agents++;
1803                 }
1804                 ast_mutex_unlock(&p->lock);
1805         }
1806         AST_LIST_UNLOCK(&agents);
1807         if ( !count_agents ) 
1808                 ast_cli(a->fd, "No Agents are configured in %s\n",config);
1809         else 
1810                 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1811         ast_cli(a->fd, "\n");
1812                         
1813         return CLI_SUCCESS;
1814 }
1815
1816
1817 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1818 {
1819         struct agent_pvt *p;
1820         char username[AST_MAX_BUF];
1821         char location[AST_MAX_BUF] = "";
1822         char talkingto[AST_MAX_BUF] = "";
1823         char music[AST_MAX_BUF];
1824         int count_agents = 0;           /* Number of agents configured */
1825         int online_agents = 0;          /* Number of online agents */
1826         int agent_status = 0;           /* 0 means offline, 1 means online */
1827
1828         switch (cmd) {
1829         case CLI_INIT:
1830                 e->command = "agent show online";
1831                 e->usage =
1832                         "Usage: agent show online\n"
1833                         "       Provides a list of all online agents.\n";
1834                 return NULL;
1835         case CLI_GENERATE:
1836                 return NULL;
1837         }
1838
1839         if (a->argc != 3)
1840                 return CLI_SHOWUSAGE;
1841
1842         AST_LIST_LOCK(&agents);
1843         AST_LIST_TRAVERSE(&agents, p, list) {
1844                 agent_status = 0;       /* reset it to offline */
1845                 ast_mutex_lock(&p->lock);
1846                 if (!ast_strlen_zero(p->name))
1847                         snprintf(username, sizeof(username), "(%s) ", p->name);
1848                 else
1849                         username[0] = '\0';
1850                 if (p->chan) {
1851                         snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1852                         if (p->owner && ast_bridged_channel(p->owner)) 
1853                                 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1854                         else 
1855                                 strcpy(talkingto, " is idle");
1856                         agent_status = 1;
1857                         online_agents++;
1858                 } else if (!ast_strlen_zero(p->loginchan)) {
1859                         snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1860                         talkingto[0] = '\0';
1861                         agent_status = 1;
1862                         online_agents++;
1863                         if (p->acknowledged)
1864                                 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1865                 }
1866                 if (!ast_strlen_zero(p->moh))
1867                         snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1868                 if (agent_status)
1869                         ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
1870                 count_agents++;
1871                 ast_mutex_unlock(&p->lock);
1872         }
1873         AST_LIST_UNLOCK(&agents);
1874         if (!count_agents) 
1875                 ast_cli(a->fd, "No Agents are configured in %s\n", config);
1876         else
1877                 ast_cli(a->fd, "%d agents online\n", online_agents);
1878         ast_cli(a->fd, "\n");
1879         return CLI_SUCCESS;
1880 }
1881
1882 static const char agent_logoff_usage[] =
1883 "Usage: agent logoff <channel> [soft]\n"
1884 "       Sets an agent as no longer logged in.\n"
1885 "       If 'soft' is specified, do not hangup existing calls.\n";
1886
1887 static struct ast_cli_entry cli_agents[] = {
1888         AST_CLI_DEFINE(agents_show, "Show status of agents"),
1889         AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
1890         AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
1891 };
1892
1893 /*!
1894  * Called by the AgentLogin application (from the dial plan).
1895  * 
1896  * \brief Log in agent application.
1897  *
1898  * \param chan
1899  * \param data
1900  * \returns
1901  * \sa agentmonitoroutgoing_exec(), load_module().
1902  */
1903 static int login_exec(struct ast_channel *chan, void *data)
1904 {
1905         int res=0;
1906         int tries = 0;
1907         int max_login_tries = maxlogintries;
1908         struct agent_pvt *p;
1909         struct ast_module_user *u;
1910         int login_state = 0;
1911         char user[AST_MAX_AGENT] = "";
1912         char pass[AST_MAX_AGENT];
1913         char agent[AST_MAX_AGENT] = "";
1914         char xpass[AST_MAX_AGENT] = "";
1915         char *errmsg;
1916         char *parse;
1917         AST_DECLARE_APP_ARGS(args,
1918                              AST_APP_ARG(agent_id);
1919                              AST_APP_ARG(options);
1920                              AST_APP_ARG(extension);
1921                 );
1922         const char *tmpoptions = NULL;
1923         int play_announcement = 1;
1924         char agent_goodbye[AST_MAX_FILENAME_LEN];
1925         int update_cdr = updatecdr;
1926         char *filename = "agent-loginok";
1927
1928         u = ast_module_user_add(chan);
1929
1930         parse = ast_strdupa(data);
1931
1932         AST_STANDARD_APP_ARGS(args, parse);
1933
1934         ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1935
1936         ast_channel_lock(chan);
1937         /* Set Channel Specific Login Overrides */
1938         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1939                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1940                 if (max_login_tries < 0)
1941                         max_login_tries = 0;
1942                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1943                 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1944         }
1945         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1946                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1947                         update_cdr = 1;
1948                 else
1949                         update_cdr = 0;
1950                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1951                 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1952         }
1953         if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1954                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1955                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1956                 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1957         }
1958         ast_channel_unlock(chan);
1959         /* End Channel Specific Login Overrides */
1960         
1961         if (!ast_strlen_zero(args.options)) {
1962                 if (strchr(args.options, 's')) {
1963                         play_announcement = 0;
1964                 }
1965         }
1966
1967         if (chan->_state != AST_STATE_UP)
1968                 res = ast_answer(chan);
1969         if (!res) {
1970                 if (!ast_strlen_zero(args.agent_id))
1971                         ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1972                 else
1973                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1974         }
1975         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1976                 tries++;
1977                 /* Check for password */
1978                 AST_LIST_LOCK(&agents);
1979                 AST_LIST_TRAVERSE(&agents, p, list) {
1980                         if (!strcmp(p->agent, user) && !p->pending)
1981                                 ast_copy_string(xpass, p->password, sizeof(xpass));
1982                 }
1983                 AST_LIST_UNLOCK(&agents);
1984                 if (!res) {
1985                         if (!ast_strlen_zero(xpass))
1986                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1987                         else
1988                                 pass[0] = '\0';
1989                 }
1990                 errmsg = "agent-incorrect";
1991
1992 #if 0
1993                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1994 #endif          
1995
1996                 /* Check again for accuracy */
1997                 AST_LIST_LOCK(&agents);
1998                 AST_LIST_TRAVERSE(&agents, p, list) {
1999                         int unlock_channel = 1;
2000                         ast_channel_lock(chan);
2001                         ast_mutex_lock(&p->lock);
2002                         if (!strcmp(p->agent, user) &&
2003                             !strcmp(p->password, pass) && !p->pending) {
2004                                 login_state = 1; /* Successful Login */
2005
2006                                 /* Ensure we can't be gotten until we're done */
2007                                 p->lastdisc = ast_tvnow();
2008                                 p->lastdisc.tv_sec++;
2009
2010                                 /* Set Channel Specific Agent Overrides */
2011                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2012                                         if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
2013                                                 p->ackcall = 2;
2014                                         else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
2015                                                 p->ackcall = 1;
2016                                         else
2017                                                 p->ackcall = 0;
2018                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2019                                         ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
2020                                 } else {
2021                                         p->ackcall = ackcall;
2022                                 }
2023                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
2024                                         p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
2025                                         if (p->autologoff < 0)
2026                                                 p->autologoff = 0;
2027                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2028                                         ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
2029                                 } else {
2030                                         p->autologoff = autologoff;
2031                                 }
2032                                 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
2033                                         p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
2034                                         if (p->wrapuptime < 0)
2035                                                 p->wrapuptime = 0;
2036                                         tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2037                                         ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
2038                                 } else {
2039                                         p->wrapuptime = wrapuptime;
2040                                 }
2041                                 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDMTF");
2042                                 if (!ast_strlen_zero(tmpoptions)) {
2043                                         p->acceptdtmf = *tmpoptions;
2044                                         ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
2045                                 }
2046                                 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
2047                                 if (!ast_strlen_zero(tmpoptions)) {
2048                                         p->enddtmf = *tmpoptions;
2049                                         ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
2050                                 }
2051                                 ast_channel_unlock(chan);
2052                                 unlock_channel = 0;
2053                                 /* End Channel Specific Agent Overrides */
2054                                 if (!p->chan) {
2055                                         long logintime;
2056                                         snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
2057
2058                                         p->loginchan[0] = '\0';
2059                                         p->logincallerid[0] = '\0';
2060                                         p->acknowledged = 0;
2061                                         
2062                                         ast_mutex_unlock(&p->lock);
2063                                         AST_LIST_UNLOCK(&agents);
2064                                         if( !res && play_announcement==1 )
2065                                                 res = ast_streamfile(chan, filename, chan->language);
2066                                         if (!res)
2067                                                 ast_waitstream(chan, "");
2068                                         AST_LIST_LOCK(&agents);
2069                                         ast_mutex_lock(&p->lock);
2070                                         if (!res) {
2071                                                 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
2072                                                 if (res)
2073                                                         ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
2074                                         }
2075                                         if (!res) {
2076                                                 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
2077                                                 if (res)
2078                                                         ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
2079                                         }
2080                                         /* Check once more just in case */
2081                                         if (p->chan)
2082                                                 res = -1;
2083                                         if (!res) {
2084                                                 ast_indicate_data(chan, AST_CONTROL_HOLD, 
2085                                                         S_OR(p->moh, NULL), 
2086                                                         !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2087                                                 if (p->loginstart == 0)
2088                                                         time(&p->loginstart);
2089                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2090                                                               "Agent: %s\r\n"
2091                                                               "Channel: %s\r\n"
2092                                                               "Uniqueid: %s\r\n",
2093                                                               p->agent, chan->name, chan->uniqueid);
2094                                                 if (update_cdr && chan->cdr)
2095                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2096                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
2097                                                 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
2098                                                                     ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
2099                                                 /* Login this channel and wait for it to go away */
2100                                                 p->chan = chan;
2101                                                 if (p->ackcall > 1)
2102                                                         check_beep(p, 0);
2103                                                 else
2104                                                         check_availability(p, 0);
2105                                                 ast_mutex_unlock(&p->lock);
2106                                                 AST_LIST_UNLOCK(&agents);
2107                                                 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2108                                                 while (res >= 0) {
2109                                                         ast_mutex_lock(&p->lock);
2110                                                         if (p->deferlogoff && p->chan) {
2111                                                                 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
2112                                                                 p->deferlogoff = 0;
2113                                                         }
2114                                                         if (p->chan != chan)
2115                                                                 res = -1;
2116                                                         ast_mutex_unlock(&p->lock);
2117                                                         /* Yield here so other interested threads can kick in. */
2118                                                         sched_yield();
2119                                                         if (res)
2120                                                                 break;
2121
2122                                                         AST_LIST_LOCK(&agents);
2123                                                         ast_mutex_lock(&p->lock);
2124                                                         if (p->lastdisc.tv_sec) {
2125                                                                 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
2126                                                                         ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
2127                                                                         p->lastdisc = ast_tv(0, 0);
2128                                                                         ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2129                                                                         if (p->ackcall > 1)
2130                                                                                 check_beep(p, 0);
2131                                                                         else
2132                                                                                 check_availability(p, 0);
2133                                                                 }
2134                                                         }
2135                                                         ast_mutex_unlock(&p->lock);
2136                                                         AST_LIST_UNLOCK(&agents);
2137                                                         /*      Synchronize channel ownership between call to agent and itself. */
2138                                                         ast_mutex_lock( &p->app_lock );
2139                                                         ast_mutex_lock(&p->lock);
2140                                                         p->owning_app = pthread_self();
2141                                                         ast_mutex_unlock(&p->lock);
2142                                                         if (p->ackcall > 1) 
2143                                                                 res = agent_ack_sleep(p);
2144                                                         else
2145                                                                 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2146                                                         ast_mutex_unlock( &p->app_lock );
2147                                                         if ((p->ackcall > 1)  && (res == 1)) {
2148                                                                 AST_LIST_LOCK(&agents);
2149                                                                 ast_mutex_lock(&p->lock);
2150                                                                 check_availability(p, 0);
2151                                                                 ast_mutex_unlock(&p->lock);
2152                                                                 AST_LIST_UNLOCK(&agents);
2153                                                                 res = 0;
2154                                                         }
2155                                                         sched_yield();
2156                                                 }
2157                                                 ast_mutex_lock(&p->lock);
2158                                                 if (res && p->owner) 
2159                                                         ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
2160                                                 /* Log us off if appropriate */
2161                                                 if (p->chan == chan) {
2162                                                         p->chan = NULL;
2163                                                         p->inherited_devicestate = -1;
2164                                                 }
2165                                                 p->acknowledged = 0;
2166                                                 logintime = time(NULL) - p->loginstart;
2167                                                 p->loginstart = 0;
2168                                                 ast_mutex_unlock(&p->lock);
2169                                                 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2170                                                               "Agent: %s\r\n"
2171                                                               "Logintime: %ld\r\n"
2172                                                               "Uniqueid: %s\r\n",
2173                                                               p->agent, logintime, chan->uniqueid);
2174                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2175                                                 ast_verb(2, "Agent '%s' logged out\n", p->agent);
2176                                                 /* If there is no owner, go ahead and kill it now */
2177                                                 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
2178                                                 if (p->dead && !p->owner) {
2179                                                         ast_mutex_destroy(&p->lock);
2180                                                         ast_mutex_destroy(&p->app_lock);
2181                                                         ast_free(p);
2182                                                 }
2183                                         }
2184                                         else {
2185                                                 ast_mutex_unlock(&p->lock);
2186                                                 p = NULL;
2187                                         }
2188                                         res = -1;
2189                                 } else {
2190                                         ast_mutex_unlock(&p->lock);
2191                                         errmsg = "agent-alreadyon";
2192                                         p = NULL;
2193                                 }
2194                                 break;
2195                         }
2196                         ast_mutex_unlock(&p->lock);
2197                         if (unlock_channel) {
2198                                 ast_channel_unlock(chan);
2199                         }
2200                 }
2201                 if (!p)
2202                         AST_LIST_UNLOCK(&agents);
2203
2204                 if (!res && (max_login_tries==0 || tries < max_login_tries))
2205                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2206         }
2207                 
2208         if (!res)
2209                 res = ast_safe_sleep(chan, 500);
2210
2211         ast_module_user_remove(u);
2212         
2213         return -1;
2214 }
2215
2216 /*!
2217  *  \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2218  *
2219  * \param chan
2220  * \param data
2221  * \returns
2222  * \sa login_exec(), load_module().
2223  */
2224 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2225 {
2226         int exitifnoagentid = 0;
2227         int nowarnings = 0;
2228         int changeoutgoing = 0;
2229         int res = 0;
2230         char agent[AST_MAX_AGENT];
2231
2232         if (data) {
2233                 if (strchr(data, 'd'))
2234                         exitifnoagentid = 1;
2235                 if (strchr(data, 'n'))
2236                         nowarnings = 1;
2237                 if (strchr(data, 'c'))
2238                         changeoutgoing = 1;
2239         }
2240         if (chan->cid.cid_num) {
2241                 const char *tmp;
2242                 char agentvar[AST_MAX_BUF];
2243                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2244                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2245                         struct agent_pvt *p;
2246                         ast_copy_string(agent, tmp, sizeof(agent));
2247                         AST_LIST_LOCK(&agents);
2248                         AST_LIST_TRAVERSE(&agents, p, list) {
2249                                 if (!strcasecmp(p->agent, tmp)) {
2250                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2251                                         __agent_start_monitoring(chan, p, 1);
2252                                         break;
2253                                 }
2254                         }
2255                         AST_LIST_UNLOCK(&agents);
2256                         
2257                 } else {
2258                         res = -1;
2259                         if (!nowarnings)
2260                                 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);
2261                 }
2262         } else {
2263                 res = -1;
2264                 if (!nowarnings)
2265                         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");
2266         }
2267         if (res) {
2268                 if (exitifnoagentid)
2269                         return res;
2270         }
2271         return 0;
2272 }
2273
2274 /*!
2275  * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
2276  */
2277 static void dump_agents(void)
2278 {
2279         struct agent_pvt *cur_agent = NULL;
2280         char buf[256];
2281
2282         AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2283                 if (cur_agent->chan)
2284                         continue;
2285
2286                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2287                         snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2288                         if (ast_db_put(pa_family, cur_agent->agent, buf))
2289                                 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
2290                         else
2291                                 ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2292                 } else {
2293                         /* Delete -  no agent or there is an error */
2294                         ast_db_del(pa_family, cur_agent->agent);
2295                 }
2296         }
2297 }
2298
2299 /*!
2300  * \brief Reload the persistent agents from astdb.
2301  */
2302 static void reload_agents(void)
2303 {
2304         char *agent_num;
2305         struct ast_db_entry *db_tree;
2306         struct ast_db_entry *entry;
2307         struct agent_pvt *cur_agent;
2308         char agent_data[256];
2309         char *parse;
2310         char *agent_chan;
2311         char *agent_callerid;
2312
2313         db_tree = ast_db_gettree(pa_family, NULL);
2314
2315         AST_LIST_LOCK(&agents);
2316         for (entry = db_tree; entry; entry = entry->next) {
2317                 agent_num = entry->key + strlen(pa_family) + 2;
2318                 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2319                         ast_mutex_lock(&cur_agent->lock);
2320                         if (strcmp(agent_num, cur_agent->agent) == 0)
2321                                 break;
2322                         ast_mutex_unlock(&cur_agent->lock);
2323                 }
2324                 if (!cur_agent) {
2325                         ast_db_del(pa_family, agent_num);
2326                         continue;
2327                 } else
2328                         ast_mutex_unlock(&cur_agent->lock);
2329                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2330                         ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
2331                         parse = agent_data;
2332                         agent_chan = strsep(&parse, ";");
2333                         agent_callerid = strsep(&parse, ";");
2334                         ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2335                         if (agent_callerid) {
2336                                 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2337                                 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2338                         } else
2339                                 cur_agent->logincallerid[0] = '\0';
2340                         if (cur_agent->loginstart == 0)
2341                                 time(&cur_agent->loginstart);
2342                         ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent); 
2343                 }
2344         }
2345         AST_LIST_UNLOCK(&agents);
2346         if (db_tree) {
2347                 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
2348                 ast_db_freetree(db_tree);
2349         }
2350 }
2351
2352 /*! \brief Part of PBX channel interface */
2353 static int agent_devicestate(void *data)
2354 {
2355         struct agent_pvt *p;
2356         char *s;
2357         ast_group_t groupmatch;
2358         int groupoff;
2359         int res = AST_DEVICE_INVALID;
2360         
2361         s = data;
2362         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
2363                 groupmatch = (1 << groupoff);
2364         else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2365                 groupmatch = (1 << groupoff);
2366         } else 
2367                 groupmatch = 0;
2368
2369         /* Check actual logged in agents first */
2370         AST_LIST_LOCK(&agents);
2371         AST_LIST_TRAVERSE(&agents, p, list) {
2372                 ast_mutex_lock(&p->lock);
2373                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2374                         if (p->owner) {
2375                                 if (res != AST_DEVICE_INUSE)
2376                                         res = AST_DEVICE_BUSY;
2377                         } else if (p->inherited_devicestate > -1) {
2378                                 res = p->inherited_devicestate;
2379                         } else {
2380                                 if (res == AST_DEVICE_BUSY)
2381                                         res = AST_DEVICE_INUSE;
2382                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2383                                         if (res == AST_DEVICE_INVALID)
2384                                                 res = AST_DEVICE_UNKNOWN;
2385                                 } else if (res == AST_DEVICE_INVALID)   
2386                                         res = AST_DEVICE_UNAVAILABLE;
2387                         }
2388                         if (!strcmp(data, p->agent)) {
2389                                 ast_mutex_unlock(&p->lock);
2390                                 break;
2391                         }
2392                 }
2393                 ast_mutex_unlock(&p->lock);
2394         }
2395         AST_LIST_UNLOCK(&agents);
2396         return res;
2397 }
2398
2399 /*!
2400  * \note This function expects the agent list to be locked
2401  */
2402 static struct agent_pvt *find_agent(char *agentid)
2403 {
2404         struct agent_pvt *cur;
2405
2406         AST_LIST_TRAVERSE(&agents, cur, list) {
2407                 if (!strcmp(cur->agent, agentid))
2408                         break;  
2409         }
2410
2411         return cur;     
2412 }
2413
2414 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2415 {
2416         char *parse;    
2417         AST_DECLARE_APP_ARGS(args,
2418                 AST_APP_ARG(agentid);
2419                 AST_APP_ARG(item);
2420         );
2421         char *tmp;
2422         struct agent_pvt *agent;
2423
2424         buf[0] = '\0';
2425
2426         if (ast_strlen_zero(data)) {
2427                 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2428                 return -1;
2429         }
2430
2431         parse = ast_strdupa(data);
2432
2433         AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2434         if (!args.item)
2435                 args.item = "status";
2436
2437         AST_LIST_LOCK(&agents);
2438
2439         if (!(agent = find_agent(args.agentid))) {
2440                 AST_LIST_UNLOCK(&agents);
2441                 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2442                 return -1;
2443         }
2444
2445         if (!strcasecmp(args.item, "status")) {
2446                 char *status = "LOGGEDOUT";
2447                 if (agent->chan || !ast_strlen_zero(agent->loginchan)) 
2448                         status = "LOGGEDIN";    
2449                 ast_copy_string(buf, status, len);
2450         } else if (!strcasecmp(args.item, "password")) 
2451                 ast_copy_string(buf, agent->password, len);
2452         else if (!strcasecmp(args.item, "name"))
2453                 ast_copy_string(buf, agent->name, len);
2454         else if (!strcasecmp(args.item, "mohclass"))
2455                 ast_copy_string(buf, agent->moh, len);
2456         else if (!strcasecmp(args.item, "channel")) {
2457                 if (agent->chan) {
2458                         ast_copy_string(buf, agent->chan->name, len);
2459                         tmp = strrchr(buf, '-');
2460                         if (tmp)
2461                                 *tmp = '\0';
2462                 } 
2463         } else if (!strcasecmp(args.item, "exten"))
2464                 ast_copy_string(buf, agent->loginchan, len);    
2465
2466         AST_LIST_UNLOCK(&agents);
2467
2468         return 0;
2469 }
2470
2471 struct ast_custom_function agent_function = {
2472         .name = "AGENT",
2473         .synopsis = "Gets information about an Agent",
2474         .syntax = "AGENT(<agentid>[:item])",
2475         .read = function_agent,
2476         .desc = "The valid items to retrieve are:\n"
2477         "- status (default)      The status of the agent\n"
2478         "                          LOGGEDIN | LOGGEDOUT\n"
2479         "- password              The password of the agent\n"
2480         "- name                  The name of the agent\n"
2481         "- mohclass              MusicOnHold class\n"
2482         "- exten                 The callback extension for the Agent (AgentCallbackLogin)\n"
2483         "- channel               The name of the active channel for the Agent (AgentLogin)\n"
2484 };
2485
2486
2487 /*!
2488  * \brief Initialize the Agents module.
2489  * This function is being called by Asterisk when loading the module. 
2490  * Among other things it registers applications, cli commands and reads the cofiguration file.
2491  *
2492  * \returns int Always 0.
2493  */
2494 static int load_module(void)
2495 {
2496         /* Make sure we can register our agent channel type */
2497         if (ast_channel_register(&agent_tech)) {
2498                 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2499                 return AST_MODULE_LOAD_FAILURE;
2500         }
2501         /* Read in the config */
2502         if (!read_agent_config(0))
2503                 return AST_MODULE_LOAD_DECLINE;
2504         if (persistent_agents)
2505                 reload_agents();
2506         /* Dialplan applications */
2507         ast_register_application(app, login_exec, synopsis, descrip);
2508         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2509
2510         /* Manager commands */
2511         ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2512         ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2513
2514         /* CLI Commands */
2515         ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2516
2517         /* Dialplan Functions */
2518         ast_custom_function_register(&agent_function);
2519
2520         agent_devicestate_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
2521                 agent_devicestate_cb, NULL, AST_EVENT_IE_END);
2522
2523         return AST_MODULE_LOAD_SUCCESS;
2524 }
2525
2526 static int reload(void)
2527 {
2528         if (!read_agent_config(1)) {
2529                 if (persistent_agents)
2530                         reload_agents();
2531         }
2532         return 0;
2533 }
2534
2535 static int unload_module(void)
2536 {
2537         struct agent_pvt *p;
2538         /* First, take us out of the channel loop */
2539         ast_channel_unregister(&agent_tech);
2540         /* Delete devicestate subscription */
2541         if (agent_devicestate_sub) {
2542                 agent_devicestate_sub = ast_event_unsubscribe(agent_devicestate_sub);
2543         }
2544         /* Unregister dialplan functions */
2545         ast_custom_function_unregister(&agent_function);        
2546         /* Unregister CLI commands */
2547         ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2548         /* Unregister dialplan applications */
2549         ast_unregister_application(app);
2550         ast_unregister_application(app3);
2551         /* Unregister manager command */
2552         ast_manager_unregister("Agents");
2553         ast_manager_unregister("AgentLogoff");
2554         /* Unregister channel */
2555         AST_LIST_LOCK(&agents);
2556         /* Hangup all interfaces if they have an owner */
2557         while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2558                 if (p->owner)
2559                         ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2560                 ast_free(p);
2561         }
2562         AST_LIST_UNLOCK(&agents);
2563         return 0;
2564 }
2565
2566 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
2567                 .load = load_module,
2568                 .unload = unload_module,
2569                 .reload = reload,
2570                );