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