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