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