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