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