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