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