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