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