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