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