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