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