Rework channel structure to eliminate "pvt" portion of channel (bug #3573)
[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                         /* Note that we don't hangup if it's not a callback because Asterisk will do it
385                            for us when the PBX instance that called login finishes */
386                         if (!ast_strlen_zero(p->loginchan)) {
387                                 p->chan->_bridge = NULL;
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) {
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                 /* If they're dead, go ahead and hang up on the agent now */
643                 if (!ast_strlen_zero(p->loginchan)) {
644                         /* Store last disconnect time */
645                         if (p->wrapuptime) {
646                                 gettimeofday(&p->lastdisc, NULL);
647                                 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
648                                 if (p->lastdisc.tv_usec >= 1000000) {
649                                         p->lastdisc.tv_usec -= 1000000;
650                                         p->lastdisc.tv_sec++;
651                                 }
652                                 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
653                         } else
654                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
655                         if (p->chan) {
656                                 /* Recognize the hangup and pass it along immediately */
657                                 ast_hangup(p->chan);
658                                 p->chan = NULL;
659                         }
660                         ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
661                         if (howlong  && p->autologoff && (howlong > p->autologoff)) {
662                                 char agent[AST_MAX_AGENT] = "";
663                                 long logintime = time(NULL) - p->loginstart;
664                                 p->loginstart = 0;
665                                 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
666                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
667                                         "Agent: %s\r\n"
668                                         "Loginchan: %s\r\n"
669                                         "Logintime: %ld\r\n"
670                                         "Reason: Autologoff\r\n"
671                                         "Uniqueid: %s\r\n",
672                                         p->agent, p->loginchan, logintime, ast->uniqueid);
673                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
674                                 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
675                                 p->loginchan[0] = '\0';
676                             ast_device_state_changed("Agent/%s", p->agent);
677                         }
678                 } else if (p->dead) {
679                         ast_mutex_lock(&p->chan->lock);
680                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
681                         ast_mutex_unlock(&p->chan->lock);
682                 } else {
683                         ast_mutex_lock(&p->chan->lock);
684                         ast_moh_start(p->chan, p->moh);
685                         ast_mutex_unlock(&p->chan->lock);
686                 }
687         }
688 #if 0
689                 ast_mutex_unlock(&p->lock);
690                 /* Release ownership of the agent to other threads (presumably running the login app). */
691                 ast_mutex_unlock(&p->app_lock);
692         } else if (p->dead) {
693                 /* Go ahead and lose it */
694                 ast_mutex_unlock(&p->lock);
695                 /* Release ownership of the agent to other threads (presumably running the login app). */
696                 ast_mutex_unlock(&p->app_lock);
697         } else {
698                 ast_mutex_unlock(&p->lock);
699                 /* Release ownership of the agent to other threads (presumably running the login app). */
700                 ast_mutex_unlock(&p->app_lock);
701         }
702 #endif  
703         ast_mutex_unlock(&p->lock);
704
705         if (p->pending) {
706                 ast_mutex_lock(&agentlock);
707                 agent_unlink(p);
708                 ast_mutex_unlock(&agentlock);
709         }
710         if (p->abouttograb) {
711                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
712                    kill it later */
713                 p->abouttograb = 0;
714         } else if (p->dead) {
715                 ast_mutex_destroy(&p->lock);
716                 ast_mutex_destroy(&p->app_lock);
717                 free(p);
718         } else {
719                 if (p->chan) {
720                         /* Not dead -- check availability now */
721                         ast_mutex_lock(&p->lock);
722                         /* Store last disconnect time */
723                         gettimeofday(&p->lastdisc, NULL);
724                         ast_mutex_unlock(&p->lock);
725                 }
726                 /* Release ownership of the agent to other threads (presumably running the login app). */
727                 ast_mutex_unlock(&p->app_lock);
728         }
729         return 0;
730 }
731
732 static int agent_cont_sleep( void *data )
733 {
734         struct agent_pvt *p;
735         struct timeval tv;
736         int res;
737
738         p = (struct agent_pvt *)data;
739
740         ast_mutex_lock(&p->lock);
741         res = p->app_sleep_cond;
742         if (p->lastdisc.tv_sec) {
743                 gettimeofday(&tv, NULL);
744                 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
745                         (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) 
746                         res = 1;
747         }
748         ast_mutex_unlock(&p->lock);
749 #if 0
750         if( !res )
751                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
752 #endif          
753         return res;
754 }
755
756 static int agent_ack_sleep( void *data )
757 {
758         struct agent_pvt *p;
759         int res=0;
760         int to = 1000;
761         struct ast_frame *f;
762
763         /* Wait a second and look for something */
764
765         p = (struct agent_pvt *)data;
766         if (p->chan) {
767                 for(;;) {
768                         to = ast_waitfor(p->chan, to);
769                         if (to < 0) {
770                                 res = -1;
771                                 break;
772                         }
773                         if (!to) {
774                                 res = 0;
775                                 break;
776                         }
777                         f = ast_read(p->chan);
778                         if (!f) {
779                                 res = -1;
780                                 break;
781                         }
782                         if (f->frametype == AST_FRAME_DTMF)
783                                 res = f->subclass;
784                         else
785                                 res = 0;
786                         ast_frfree(f);
787                         ast_mutex_lock(&p->lock);
788                         if (!p->app_sleep_cond) {
789                                 ast_mutex_unlock(&p->lock);
790                                 res = 0;
791                                 break;
792                         } else if (res == '#') {
793                                 ast_mutex_unlock(&p->lock);
794                                 res = 1;
795                                 break;
796                         }
797                         ast_mutex_unlock(&p->lock);
798                         res = 0;
799                 }
800         } else
801                 res = -1;
802         return res;
803 }
804
805 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
806 {
807         struct agent_pvt *p;
808         struct ast_channel *ret=NULL;
809         
810
811         p = bridge->tech_pvt;
812         if (chan == p->chan)
813                 ret = bridge->_bridge;
814         else if (chan == bridge->_bridge)
815                 ret = p->chan;
816         if (option_debug)
817                 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
818         return ret;
819 }
820
821 /*--- agent_new: Create new agent channel ---*/
822 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
823 {
824         struct ast_channel *tmp;
825         struct ast_frame null_frame = { AST_FRAME_NULL };
826 #if 0
827         if (!p->chan) {
828                 ast_log(LOG_WARNING, "No channel? :(\n");
829                 return NULL;
830         }
831 #endif  
832         tmp = ast_channel_alloc(0);
833         if (tmp) {
834                 tmp->tech = &agent_tech;
835                 if (p->chan) {
836                         tmp->nativeformats = p->chan->nativeformats;
837                         tmp->writeformat = p->chan->writeformat;
838                         tmp->rawwriteformat = p->chan->writeformat;
839                         tmp->readformat = p->chan->readformat;
840                         tmp->rawreadformat = p->chan->readformat;
841                         strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
842                         strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
843                         strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
844                 } else {
845                         tmp->nativeformats = AST_FORMAT_SLINEAR;
846                         tmp->writeformat = AST_FORMAT_SLINEAR;
847                         tmp->rawwriteformat = AST_FORMAT_SLINEAR;
848                         tmp->readformat = AST_FORMAT_SLINEAR;
849                         tmp->rawreadformat = AST_FORMAT_SLINEAR;
850                 }
851                 if (p->pending)
852                         snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
853                 else
854                         snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
855                 tmp->type = channeltype;
856                 /* Safe, agentlock already held */
857                 ast_setstate(tmp, state);
858                 tmp->tech_pvt = p;
859                 p->owner = tmp;
860                 ast_mutex_lock(&usecnt_lock);
861                 usecnt++;
862                 ast_mutex_unlock(&usecnt_lock);
863                 ast_update_use_count();
864                 tmp->priority = 1;
865                 /* Wake up and wait for other applications (by definition the login app)
866                  * to release this channel). Takes ownership of the agent channel
867                  * to this thread only.
868                  * For signalling the other thread, ast_queue_frame is used until we
869                  * can safely use signals for this purpose. The pselect() needs to be
870                  * implemented in the kernel for this.
871                  */
872                 p->app_sleep_cond = 0;
873                 if( ast_mutex_trylock(&p->app_lock) )
874                 {
875                         if (p->chan) {
876                                 ast_queue_frame(p->chan, &null_frame);
877                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
878                                 ast_mutex_lock(&p->app_lock);
879                                 ast_mutex_lock(&p->lock);
880                         }
881                         if( !p->chan )
882                         {
883                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
884                                 p->owner = NULL;
885                                 tmp->tech_pvt = NULL;
886                                 p->app_sleep_cond = 1;
887                                 ast_channel_free( tmp );
888                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
889                                 ast_mutex_unlock(&p->app_lock);
890                                 return NULL;
891                         }
892                 }
893                 p->owning_app = pthread_self();
894                 /* After the above step, there should not be any blockers. */
895                 if (p->chan) {
896                         if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
897                                 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
898                                 CRASH;
899                         }
900                         ast_moh_stop(p->chan);
901                 }
902         } else
903                 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
904         return tmp;
905 }
906
907
908 /*--- read_agent_config: Read configuration data (agents.conf) ---*/
909 static int read_agent_config(void)
910 {
911         struct ast_config *cfg;
912         struct ast_variable *v;
913         struct agent_pvt *p, *pl, *pn;
914         char *general_val;
915
916         group = 0;
917         autologoff = 0;
918         wrapuptime = 0;
919         ackcall = 0;
920         cfg = ast_config_load(config);
921         if (!cfg) {
922                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
923                 return 0;
924         }
925         ast_mutex_lock(&agentlock);
926         p = agents;
927         while(p) {
928                 p->dead = 1;
929                 p = p->next;
930         }
931         strncpy(moh, "default", sizeof(moh) - 1);
932         /* set the default recording values */
933         recordagentcalls = 0;
934         createlink = 0;
935         strncpy(recordformat, "wav", sizeof(recordformat) - 1);
936         strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
937         urlprefix[0] = '\0';
938         savecallsin[0] = '\0';
939
940         /* Read in [general] section for persistance */
941         if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
942                 persistent_agents = ast_true(general_val);
943
944         /* Read in the [agents] section */
945         v = ast_variable_browse(cfg, "agents");
946         while(v) {
947                 /* Create the interface list */
948                 if (!strcasecmp(v->name, "agent")) {
949                         add_agent(v->value, 0);
950                 } else if (!strcasecmp(v->name, "group")) {
951                         group = ast_get_group(v->value);
952                 } else if (!strcasecmp(v->name, "autologoff")) {
953                         autologoff = atoi(v->value);
954                         if (autologoff < 0)
955                                 autologoff = 0;
956                 } else if (!strcasecmp(v->name, "ackcall")) {
957                         if (!strcasecmp(v->value, "always"))
958                                 ackcall = 2;
959                         else if (ast_true(v->value))
960                                 ackcall = 1;
961                         else
962                                 ackcall = 0;
963                 } else if (!strcasecmp(v->name, "wrapuptime")) {
964                         wrapuptime = atoi(v->value);
965                         if (wrapuptime < 0)
966                                 wrapuptime = 0;
967                 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
968                         maxlogintries = atoi(v->value);
969                         if (maxlogintries < 0)
970                                 maxlogintries = 0;
971                 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
972                         strcpy(agentgoodbye,v->value);
973                 } else if (!strcasecmp(v->name, "musiconhold")) {
974                         strncpy(moh, v->value, sizeof(moh) - 1);
975                 } else if (!strcasecmp(v->name, "updatecdr")) {
976                         if (ast_true(v->value))
977                                 updatecdr = 1;
978                         else
979                                 updatecdr = 0;
980                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
981                         recordagentcalls = ast_true(v->value);
982                 } else if (!strcasecmp(v->name, "createlink")) {
983                         createlink = ast_true(v->value);
984                 } else if (!strcasecmp(v->name, "recordformat")) {
985                         strncpy(recordformat, v->value, sizeof(recordformat) - 1);
986                         if (!strcasecmp(v->value, "wav49"))
987                                 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
988                         else
989                                 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
990                 } else if (!strcasecmp(v->name, "urlprefix")) {
991                         strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
992                         if (urlprefix[strlen(urlprefix) - 1] != '/')
993                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
994                 } else if (!strcasecmp(v->name, "savecallsin")) {
995                         if (v->value[0] == '/')
996                                 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
997                         else
998                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
999                         if (savecallsin[strlen(savecallsin) - 1] != '/')
1000                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1001                 } else if (!strcasecmp(v->name, "custom_beep")) {
1002                         strncpy(beep, v->value, sizeof(beep) - 1);
1003                 }
1004                 v = v->next;
1005         }
1006         p = agents;
1007         pl = NULL;
1008         while(p) {
1009                 pn = p->next;
1010                 if (p->dead) {
1011                         /* Unlink */
1012                         if (pl)
1013                                 pl->next = p->next;
1014                         else
1015                                 agents = p->next;
1016                         /* Destroy if  appropriate */
1017                         if (!p->owner) {
1018                                 if (!p->chan) {
1019                                         ast_mutex_destroy(&p->lock);
1020                                         ast_mutex_destroy(&p->app_lock);
1021                                         free(p);
1022                                 } else {
1023                                         /* Cause them to hang up */
1024                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1025                                 }
1026                         }
1027                 } else
1028                         pl = p;
1029                 p = pn;
1030         }
1031         ast_mutex_unlock(&agentlock);
1032         ast_config_destroy(cfg);
1033         return 0;
1034 }
1035
1036 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1037 {
1038         struct ast_channel *chan=NULL, *parent=NULL;
1039         struct agent_pvt *p;
1040         int res;
1041
1042         if (option_debug)
1043                 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1044         if (needlock)
1045                 ast_mutex_lock(&agentlock);
1046         p = agents;
1047         while(p) {
1048                 if (p == newlyavailable) {
1049                         p = p->next;
1050                         continue;
1051                 }
1052                 ast_mutex_lock(&p->lock);
1053                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1054                         if (option_debug)
1055                                 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1056                         /* We found a pending call, time to merge */
1057                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
1058                         parent = p->owner;
1059                         p->abouttograb = 1;
1060                         ast_mutex_unlock(&p->lock);
1061                         break;
1062                 }
1063                 ast_mutex_unlock(&p->lock);
1064                 p = p->next;
1065         }
1066         if (needlock)
1067                 ast_mutex_unlock(&agentlock);
1068         if (parent && chan)  {
1069                 if (newlyavailable->ackcall > 1) {
1070                         /* Don't do beep here */
1071                         res = 0;
1072                 } else {
1073                         if (option_debug > 2)
1074                                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1075                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1076                         if (option_debug > 2)
1077                                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1078                         if (!res) {
1079                                 res = ast_waitstream(newlyavailable->chan, "");
1080                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1081                         }
1082                 }
1083                 if (!res) {
1084                         /* Note -- parent may have disappeared */
1085                         if (p->abouttograb) {
1086                                 newlyavailable->acknowledged = 1;
1087                                 /* Safe -- agent lock already held */
1088                                 ast_setstate(parent, AST_STATE_UP);
1089                                 ast_setstate(chan, AST_STATE_UP);
1090                                 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1091                                 /* Go ahead and mark the channel as a zombie so that masquerade will
1092                                    destroy it for us, and we need not call ast_hangup */
1093                                 ast_mutex_lock(&parent->lock);
1094                                 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1095                                 ast_channel_masquerade(parent, chan);
1096                                 ast_mutex_unlock(&parent->lock);
1097                                 p->abouttograb = 0;
1098                         } else {
1099                                 if (option_debug)
1100                                         ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1101                                 agent_cleanup(newlyavailable);
1102                         }
1103                 } else {
1104                         if (option_debug)
1105                                 ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
1106                         agent_cleanup(newlyavailable);
1107                 }
1108         }
1109         return 0;
1110 }
1111
1112 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1113 {
1114         struct agent_pvt *p;
1115         int res=0;
1116
1117         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1118         if (needlock)
1119                 ast_mutex_lock(&agentlock);
1120         p = agents;
1121         while(p) {
1122                 if (p == newlyavailable) {
1123                         p = p->next;
1124                         continue;
1125                 }
1126                 ast_mutex_lock(&p->lock);
1127                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1128                         if (option_debug)
1129                                 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1130                         ast_mutex_unlock(&p->lock);
1131                         break;
1132                 }
1133                 ast_mutex_unlock(&p->lock);
1134                 p = p->next;
1135         }
1136         if (needlock)
1137                 ast_mutex_unlock(&agentlock);
1138         if (p) {
1139                 ast_mutex_unlock(&newlyavailable->lock);
1140                 if (option_debug > 2)
1141                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1142                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1143                 if (option_debug > 2)
1144                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1145                 if (!res) {
1146                         res = ast_waitstream(newlyavailable->chan, "");
1147                         if (option_debug)
1148                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1149                 }
1150                 ast_mutex_lock(&newlyavailable->lock);
1151         }
1152         return res;
1153 }
1154
1155 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1156 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1157 {
1158         struct agent_pvt *p;
1159         struct ast_channel *chan = NULL;
1160         char *s;
1161         ast_group_t groupmatch;
1162         int groupoff;
1163         int waitforagent=0;
1164         int hasagent = 0;
1165         struct timeval tv;
1166
1167         s = data;
1168         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1169                 groupmatch = (1 << groupoff);
1170         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1171                 groupmatch = (1 << groupoff);
1172                 waitforagent = 1;
1173         } else {
1174                 groupmatch = 0;
1175         }
1176
1177         /* Check actual logged in agents first */
1178         ast_mutex_lock(&agentlock);
1179         p = agents;
1180         while(p) {
1181                 ast_mutex_lock(&p->lock);
1182                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1183                                 ast_strlen_zero(p->loginchan)) {
1184                         if (p->chan)
1185                                 hasagent++;
1186                         if (!p->lastdisc.tv_sec) {
1187                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1188                                 if (!p->owner && p->chan) {
1189                                         /* Fixed agent */
1190                                         chan = agent_new(p, AST_STATE_DOWN);
1191                                 }
1192                                 if (chan) {
1193                                         ast_mutex_unlock(&p->lock);
1194                                         break;
1195                                 }
1196                         }
1197                 }
1198                 ast_mutex_unlock(&p->lock);
1199                 p = p->next;
1200         }
1201         if (!p) {
1202                 p = agents;
1203                 while(p) {
1204                         ast_mutex_lock(&p->lock);
1205                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1206                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1207                                         hasagent++;
1208                                 gettimeofday(&tv, NULL);
1209 #if 0
1210                                 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1211 #endif
1212                                 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1213                                         memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1214                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1215                                         if (!p->owner && p->chan) {
1216                                                 /* Could still get a fixed agent */
1217                                                 chan = agent_new(p, AST_STATE_DOWN);
1218                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1219                                                 /* Adjustable agent */
1220                                                 p->chan = ast_request("Local", format, p->loginchan, cause);
1221                                                 if (p->chan)
1222                                                         chan = agent_new(p, AST_STATE_DOWN);
1223                                         }
1224                                         if (chan) {
1225                                                 ast_mutex_unlock(&p->lock);
1226                                                 break;
1227                                         }
1228                                 }
1229                         }
1230                         ast_mutex_unlock(&p->lock);
1231                         p = p->next;
1232                 }
1233         }
1234
1235         if (!chan && waitforagent) {
1236                 /* No agent available -- but we're requesting to wait for one.
1237                    Allocate a place holder */
1238                 if (hasagent) {
1239                         if (option_debug)
1240                                 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1241                         p = add_agent(data, 1);
1242                         p->group = groupmatch;
1243                         chan = agent_new(p, AST_STATE_DOWN);
1244                         if (!chan) {
1245                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1246                         }
1247                 } else
1248                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1249         }
1250         if (hasagent)
1251                 *cause = AST_CAUSE_BUSY;
1252         else
1253                 *cause = AST_CAUSE_UNREGISTERED;
1254         ast_mutex_unlock(&agentlock);
1255         return chan;
1256 }
1257
1258 static int powerof(unsigned int v)
1259 {
1260         int x;
1261         for (x=0;x<32;x++) {
1262                 if (v & (1 << x)) return x;
1263         }
1264         return 0;
1265 }
1266
1267 /*--- action_agents: Manager routine for listing channels */
1268 static int action_agents(struct mansession *s, struct message *m)
1269 {
1270         struct agent_pvt *p;
1271         char *username = NULL;
1272         char *loginChan = NULL;
1273         char *talkingtoChan = NULL;
1274         char *status = NULL;
1275
1276         ast_mutex_lock(&agentlock);
1277         p = agents;
1278         while(p) {
1279                 ast_mutex_lock(&p->lock);
1280
1281                 /* Status Values:
1282                         AGENT_LOGGEDOFF - Agent isn't logged in
1283                         AGENT_IDLE      - Agent is logged in, and waiting for call
1284                         AGENT_ONCALL    - Agent is logged in, and on a call
1285                         AGENT_UNKNOWN   - Don't know anything about agent. Shouldn't ever get this. */
1286
1287                 if(!ast_strlen_zero(p->name)) {
1288                         username = p->name;
1289                 } else {
1290                         username = "None";
1291                 }
1292
1293                 /* Set a default status. It 'should' get changed. */
1294                 status = "AGENT_UNKNOWN";
1295
1296                 if(p->chan) {
1297                         loginChan = p->loginchan;
1298                         if(p->owner && p->owner->_bridge) {
1299                                 talkingtoChan = p->chan->cid.cid_num;
1300                                 status = "AGENT_ONCALL";
1301                         } else {
1302                                 talkingtoChan = "n/a";
1303                                 status = "AGENT_IDLE";
1304                         }
1305                 } else if(!ast_strlen_zero(p->loginchan)) {
1306                         loginChan = p->loginchan;
1307                         talkingtoChan = "n/a";
1308                         status = "AGENT_IDLE";
1309                         if(p->acknowledged) {
1310                                 sprintf(loginChan, " %s (Confirmed)", loginChan);
1311                         }
1312                 } else {
1313                         loginChan = "n/a";
1314                         talkingtoChan = "n/a";
1315                         status = "AGENT_LOGGEDOFF";
1316                 }
1317
1318                 ast_cli(s->fd, "Event: Agents\r\n"
1319                                 "Agent: %s\r\n"
1320                                 "Name: %s\r\n"
1321                                 "Status: %s\r\n"
1322                                 "LoggedInChan: %s\r\n"
1323                                 "LoggedInTime: %ld\r\n"
1324                                 "TalkingTo: %s\r\n"
1325                                 "\r\n",
1326                                 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1327                 ast_mutex_unlock(&p->lock);
1328                 p = p->next;
1329         }
1330         ast_mutex_unlock(&agentlock);
1331         return 0;
1332 }
1333
1334 static int agent_logoff_cmd(int fd, int argc, char **argv)
1335 {
1336         struct agent_pvt *p;
1337         char *agent = argv[2] + 6;
1338         long logintime;
1339         
1340         if (argc < 3 || argc > 4)
1341                 return RESULT_SHOWUSAGE;
1342         if (argc == 4 && strcasecmp(argv[3], "soft"))
1343                 return RESULT_SHOWUSAGE;
1344
1345         for (p=agents; p; p=p->next) {
1346                 if (!strcasecmp(p->agent, agent)) {
1347                         if (argc == 3) {
1348                                 if (p->owner) {
1349                                         ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1350                                 }
1351                                 if (p->chan) {
1352                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1353                                 }
1354                         }
1355                         logintime = time(NULL) - p->loginstart;
1356                         p->loginstart = 0;
1357                         
1358                         manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1359                                 "Agent: %s\r\n"
1360                                 "Loginchan: %s\r\n"
1361                                 "Logintime: %ld\r\n",
1362                                 p->agent, p->loginchan, logintime);
1363                         ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1364                         p->loginchan[0] = '\0';
1365                         ast_cli(fd, "Logging out %s\n", agent);
1366                         break;
1367                 }
1368         }
1369         return RESULT_SUCCESS;
1370 }
1371
1372 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1373 {
1374         struct agent_pvt *p;
1375         char name[AST_MAX_AGENT];
1376         int which = 0;
1377
1378         if (pos == 2) {
1379                 for (p=agents; p; p=p->next) {
1380                         snprintf(name, sizeof(name), "Agent/%s", p->agent);
1381                         if (!strncasecmp(word, name, strlen(word))) {
1382                                 if (++which > state) {
1383                                         return strdup(name);
1384                                 }
1385                         }
1386                 }
1387         } else if (pos == 3 && state == 0) {
1388                 return strdup("soft");
1389         }
1390         return NULL;
1391 }
1392
1393 /*--- agents_show: Show agents in cli ---*/
1394 static int agents_show(int fd, int argc, char **argv)
1395 {
1396         struct agent_pvt *p;
1397         char username[AST_MAX_BUF];
1398         char location[AST_MAX_BUF] = "";
1399         char talkingto[AST_MAX_BUF] = "";
1400         char moh[AST_MAX_BUF];
1401
1402         if (argc != 2)
1403                 return RESULT_SHOWUSAGE;
1404         ast_mutex_lock(&agentlock);
1405         p = agents;
1406         while(p) {
1407                 ast_mutex_lock(&p->lock);
1408                 if (p->pending) {
1409                         if (p->group)
1410                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1411                         else
1412                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1413                 } else {
1414                         if (!ast_strlen_zero(p->name))
1415                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1416                         else
1417                                 username[0] = '\0';
1418                         if (p->chan) {
1419                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1420                                 if (p->owner && ast_bridged_channel(p->owner)) {
1421                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1422                                 } else {
1423                                         strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1424                                 }
1425                         } else if (!ast_strlen_zero(p->loginchan)) {
1426                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1427                                 talkingto[0] = '\0';
1428                                 if (p->acknowledged)
1429                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1430                         } else {
1431                                 strncpy(location, "not logged in", sizeof(location) - 1);
1432                                 talkingto[0] = '\0';
1433                         }
1434                         if (!ast_strlen_zero(p->moh))
1435                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1436                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1437                                         username, location, talkingto, moh);
1438                 }
1439                 ast_mutex_unlock(&p->lock);
1440                 p = p->next;
1441         }
1442         ast_mutex_unlock(&agentlock);
1443         return RESULT_SUCCESS;
1444 }
1445
1446 static char show_agents_usage[] = 
1447 "Usage: show agents\n"
1448 "       Provides summary information on agents.\n";
1449
1450 static char agent_logoff_usage[] =
1451 "Usage: agent logoff <channel> [soft]\n"
1452 "       Sets an agent as no longer logged in.\n"
1453 "       If 'soft' is specified, do not hangup existing calls.\n";
1454
1455 static struct ast_cli_entry cli_show_agents = {
1456         { "show", "agents", NULL }, agents_show, 
1457         "Show status of agents", show_agents_usage, NULL };
1458
1459 static struct ast_cli_entry cli_agent_logoff = {
1460         { "agent", "logoff", NULL }, agent_logoff_cmd, 
1461         "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1462
1463 STANDARD_LOCAL_USER;
1464 LOCAL_USER_DECL;
1465
1466 /*--- __login_exec: Log in agent application ---*/
1467 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1468 {
1469         int res=0;
1470         int tries = 0;
1471         int max_login_tries = maxlogintries;
1472         struct agent_pvt *p;
1473         struct localuser *u;
1474         struct timeval tv;
1475         int login_state = 0;
1476         char user[AST_MAX_AGENT] = "";
1477         char pass[AST_MAX_AGENT];
1478         char agent[AST_MAX_AGENT] = "";
1479         char xpass[AST_MAX_AGENT] = "";
1480         char *errmsg;
1481         char info[512];
1482         char *opt_user = NULL;
1483         char *options = NULL;
1484         char option;
1485         char badoption[2];
1486         char *tmpoptions = NULL;
1487         char *context = NULL;
1488         char *exten = NULL;
1489         int play_announcement = 1;
1490         char agent_goodbye[AST_MAX_FILENAME_LEN];
1491         int update_cdr = updatecdr;
1492         char *filename = "agent-loginok";
1493         
1494         strcpy(agent_goodbye, agentgoodbye);
1495         LOCAL_USER_ADD(u);
1496
1497         /* Parse the arguments XXX Check for failure XXX */
1498         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1499         opt_user = info;
1500         /* Set Channel Specific Login Overrides */
1501         if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1502                 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1503                 if (max_login_tries < 0)
1504                         max_login_tries = 0;
1505                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1506                 if (option_verbose > 2)
1507                         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);
1508         }
1509         if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1510                 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1511                         update_cdr = 1;
1512                 else
1513                         update_cdr = 0;
1514                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1515                 if (option_verbose > 2)
1516                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1517         }
1518         if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1519                 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1520                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1521                 if (option_verbose > 2)
1522                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1523         }
1524         /* End Channel Specific Login Overrides */
1525         /* Read command line options */
1526          if( opt_user ) {
1527                 options = strchr(opt_user, '|');
1528                 if (options) {
1529                         *options = '\0';
1530                         options++;
1531                         if (callbackmode) {
1532                                 context = strchr(options, '@');
1533                                 if (context) {
1534                                         *context = '\0';
1535                                         context++;
1536                                 }
1537                                 exten = options;
1538                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1539                                 if (!*exten)
1540                                         exten = NULL;
1541                         }
1542                 }
1543                 if (options) {
1544                         while (*options) {
1545                                 option = (char)options[0];
1546                                 if ((option >= 0) && (option <= '9'))
1547                                 {
1548                                         options++;
1549                                         continue;
1550                                 }
1551                                 if (option=='s')
1552                                         play_announcement = 0;
1553                                 else {
1554                                         badoption[0] = option;
1555                                         badoption[1] = '\0';
1556                                         tmpoptions=badoption;
1557                                         if (option_verbose > 2)
1558                                                 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1559                                 }
1560                                 options++;
1561                         }
1562                 }
1563         }
1564         /* End command line options */
1565
1566         if (chan->_state != AST_STATE_UP)
1567                 res = ast_answer(chan);
1568         if (!res) {
1569                 if( opt_user && !ast_strlen_zero(opt_user))
1570                         strncpy( user, opt_user, AST_MAX_AGENT - 1);
1571                 else
1572                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1573         }
1574         while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1575                 tries++;
1576                 /* Check for password */
1577                 ast_mutex_lock(&agentlock);
1578                 p = agents;
1579                 while(p) {
1580                         if (!strcmp(p->agent, user) && !p->pending)
1581                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1582                         p = p->next;
1583                 }
1584                 ast_mutex_unlock(&agentlock);
1585                 if (!res) {
1586                         if (!ast_strlen_zero(xpass))
1587                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1588                         else
1589                                 pass[0] = '\0';
1590                 }
1591                 errmsg = "agent-incorrect";
1592
1593 #if 0
1594                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1595 #endif          
1596
1597                 /* Check again for accuracy */
1598                 ast_mutex_lock(&agentlock);
1599                 p = agents;
1600                 while(p) {
1601                         ast_mutex_lock(&p->lock);
1602                         if (!strcmp(p->agent, user) &&
1603                                 !strcmp(p->password, pass) && !p->pending) {
1604                                         login_state = 1; /* Successful Login */
1605                                         /* Set Channel Specific Agent Overides */
1606                                         if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1607                                                 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1608                                                         p->ackcall = 2;
1609                                                 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1610                                                         p->ackcall = 1;
1611                                                 else
1612                                                         p->ackcall = 0;
1613                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1614                                                 if (option_verbose > 2)
1615                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1616                                         }
1617                                         if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1618                                                 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1619                                                 if (p->autologoff < 0)
1620                                                         p->autologoff = 0;
1621                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1622                                                 if (option_verbose > 2)
1623                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1624                                         }
1625                                         if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1626                                                 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1627                                                 if (p->wrapuptime < 0)
1628                                                         p->wrapuptime = 0;
1629                                                 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1630                                                 if (option_verbose > 2)
1631                                                         ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1632                                         }
1633                                         /* End Channel Specific Agent Overides */
1634                                         if (!p->chan) {
1635                                                 char last_loginchan[80] = "";
1636                                                 long logintime;
1637                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1638
1639                                                 if (callbackmode) {
1640                                                         char tmpchan[AST_MAX_BUF] = "";
1641                                                         int pos = 0;
1642                                                         /* Retrieve login chan */
1643                                                         for (;;) {
1644                                                                 if (exten) {
1645                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1646                                                                         res = 0;
1647                                                                 } else
1648                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1649                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1650                                                                                         1, NULL))
1651                                                                         break;
1652                                                                 if (exten) {
1653                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1654                                                                         exten = NULL;
1655                                                                         pos = 0;
1656                                                                 } else {
1657                                                                         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);
1658                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1659                                                                         if (!res)
1660                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1661                                                                         if (res > 0) {
1662                                                                                 tmpchan[0] = res;
1663                                                                                 tmpchan[1] = '\0';
1664                                                                                 pos = 1;
1665                                                                         } else {
1666                                                                                 tmpchan[0] = '\0';
1667                                                                                 pos = 0;
1668                                                                         }
1669                                                                 }
1670                                                         }
1671                                                         exten = tmpchan;
1672                                                         if (!res) {
1673                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1674                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1675                                                                 else {
1676                                                                         strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1677                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1678                                                                 }
1679                                                                 if (ast_strlen_zero(p->loginchan)) {
1680                                                                         login_state = 2;
1681                                                                         filename = "agent-loggedoff";
1682                                                                 }
1683                                                                 p->acknowledged = 0;
1684                                                                 /* store/clear the global variable that stores agentid based on the callerid */
1685                                                                 if (chan->cid.cid_num) {
1686                                                                         char agentvar[AST_MAX_BUF];
1687                                                                         snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1688                                                                         if (ast_strlen_zero(p->loginchan))
1689                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1690                                                                         else
1691                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1692                                                                 }
1693                                                                 if(update_cdr && chan->cdr)
1694                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1695
1696                                                         }
1697                                                 } else {
1698                                                         p->loginchan[0] = '\0';
1699                                                         p->acknowledged = 0;
1700                                                 }
1701                                                 ast_mutex_unlock(&p->lock);
1702                                                 ast_mutex_unlock(&agentlock);
1703                                                 if( !res && play_announcement==1 )
1704                                                         res = ast_streamfile(chan, filename, chan->language);
1705                                                 if (!res)
1706                                                         ast_waitstream(chan, "");
1707                                                 ast_mutex_lock(&agentlock);
1708                                                 ast_mutex_lock(&p->lock);
1709                                                 if (!res) {
1710                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1711                                                         if (res)
1712                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1713                                                 }
1714                                                 if (!res) {
1715                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1716                                                         if (res)
1717                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1718                                                 }
1719                                                 /* Check once more just in case */
1720                                                 if (p->chan)
1721                                                         res = -1;
1722                                                 if (callbackmode && !res) {
1723                                                         /* Just say goodbye and be done with it */
1724                                                         if (!ast_strlen_zero(p->loginchan)) {
1725                                                                 if (p->loginstart == 0)
1726                                                                         time(&p->loginstart);
1727                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1728                                                                         "Agent: %s\r\n"
1729                                                                         "Loginchan: %s\r\n"
1730                                                                         "Uniqueid: %s\r\n",
1731                                                                         p->agent, p->loginchan, chan->uniqueid);
1732                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1733                                                                 if (option_verbose > 1)
1734                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1735                                                                 ast_device_state_changed("Agent/%s", p->agent);
1736                                                         } else {
1737                                                                 logintime = time(NULL) - p->loginstart;
1738                                                                 p->loginstart = 0;
1739                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1740                                                                         "Agent: %s\r\n"
1741                                                                         "Loginchan: %s\r\n"
1742                                                                         "Logintime: %ld\r\n"
1743                                                                         "Uniqueid: %s\r\n",
1744                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1745                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1746                                                                 if (option_verbose > 1)
1747                                                                         ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1748                                                                 ast_device_state_changed("Agent/%s", p->agent);
1749                                                         }
1750                                                         ast_mutex_unlock(&agentlock);
1751                                                         if (!res)
1752                                                                 res = ast_safe_sleep(chan, 500);
1753                                                         ast_mutex_unlock(&p->lock);
1754                                                         if (persistent_agents)
1755                                                                 dump_agents();
1756                                                 } else if (!res) {
1757 #ifdef HONOR_MUSIC_CLASS
1758                                                         /* check if the moh class was changed with setmusiconhold */
1759                                                         if (*(chan->musicclass))
1760                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1761 #endif                                                          
1762                                                         ast_moh_start(chan, p->moh);
1763                                                         if (p->loginstart == 0)
1764                                                                 time(&p->loginstart);
1765                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1766                                                                 "Agent: %s\r\n"
1767                                                                 "Channel: %s\r\n"
1768                                                                 "Uniqueid: %s\r\n",
1769                                                                 p->agent, chan->name, chan->uniqueid);
1770                                                         if (update_cdr && chan->cdr)
1771                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1772                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1773                                                         if (option_verbose > 1)
1774                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1775                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1776                                                         /* Login this channel and wait for it to
1777                                                            go away */
1778                                                         p->chan = chan;
1779                                                         if (p->ackcall > 1)
1780                                                                 check_beep(p, 0);
1781                                                         else
1782                                                                 check_availability(p, 0);
1783                                                         ast_mutex_unlock(&p->lock);
1784                                                         ast_mutex_unlock(&agentlock);
1785                                                         ast_device_state_changed("Agent/%s", p->agent);
1786                                                         while (res >= 0) {
1787                                                                 ast_mutex_lock(&p->lock);
1788                                                                 if (p->chan != chan)
1789                                                                         res = -1;
1790                                                                 ast_mutex_unlock(&p->lock);
1791                                                                 /* Yield here so other interested threads can kick in. */
1792                                                                 sched_yield();
1793                                                                 if (res)
1794                                                                         break;
1795
1796                                                                 ast_mutex_lock(&agentlock);
1797                                                                 ast_mutex_lock(&p->lock);
1798                                                                 if (p->lastdisc.tv_sec) {
1799                                                                         gettimeofday(&tv, NULL);
1800                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1801                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1802                                                                                         if (option_debug)
1803                                                                                                 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1804                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1805                                                                                 if (p->ackcall > 1)
1806                                                                                         check_beep(p, 0);
1807                                                                                 else
1808                                                                                         check_availability(p, 0);
1809                                                                         }
1810                                                                 }
1811                                                                 ast_mutex_unlock(&p->lock);
1812                                                                 ast_mutex_unlock(&agentlock);
1813                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1814                                                                 ast_mutex_lock( &p->app_lock );
1815                                                                 ast_mutex_lock(&p->lock);
1816                                                                 p->owning_app = pthread_self();
1817                                                                 ast_mutex_unlock(&p->lock);
1818                                                                 if (p->ackcall > 1) 
1819                                                                         res = agent_ack_sleep(p);
1820                                                                 else
1821                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1822                                                                                                         agent_cont_sleep, p );
1823                                                                 ast_mutex_unlock( &p->app_lock );
1824                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1825                                                                         ast_mutex_lock(&agentlock);
1826                                                                         ast_mutex_lock(&p->lock);
1827                                                                         check_availability(p, 0);
1828                                                                         ast_mutex_unlock(&p->lock);
1829                                                                         ast_mutex_unlock(&agentlock);
1830                                                                         res = 0;
1831                                                                 }
1832                                                                 sched_yield();
1833                                                         }
1834                                                         ast_mutex_lock(&p->lock);
1835                                                         if (res && p->owner) 
1836                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1837                                                         /* Log us off if appropriate */
1838                                                         if (p->chan == chan)
1839                                                                 p->chan = NULL;
1840                                                         p->acknowledged = 0;
1841                                                         logintime = time(NULL) - p->loginstart;
1842                                                         p->loginstart = 0;
1843                                                         ast_mutex_unlock(&p->lock);
1844                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1845                                                                 "Agent: %s\r\n"
1846                                                                 "Logintime: %ld\r\n"
1847                                                                 "Uniqueid: %s\r\n",
1848                                                                 p->agent, logintime, chan->uniqueid);
1849                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1850                                                         if (option_verbose > 1)
1851                                                                 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1852                                                         /* If there is no owner, go ahead and kill it now */
1853                                                         ast_device_state_changed("Agent/%s", p->agent);
1854                                                         if (p->dead && !p->owner) {
1855                                                                 ast_mutex_destroy(&p->lock);
1856                                                                 ast_mutex_destroy(&p->app_lock);
1857                                                                 free(p);
1858                                                         }
1859                                                 }
1860                                                 else {
1861                                                         ast_mutex_unlock(&p->lock);
1862                                                         p = NULL;
1863                                                 }
1864                                                 res = -1;
1865                                         } else {
1866                                                 ast_mutex_unlock(&p->lock);
1867                                                 errmsg = "agent-alreadyon";
1868                                                 p = NULL;
1869                                         }
1870                                         break;
1871                         }
1872                         ast_mutex_unlock(&p->lock);
1873                         p = p->next;
1874                 }
1875                 if (!p)
1876                         ast_mutex_unlock(&agentlock);
1877
1878                 if (!res && (max_login_tries==0 || tries < max_login_tries))
1879                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1880         }
1881                 
1882         LOCAL_USER_REMOVE(u);
1883         if (!res)
1884                 res = ast_safe_sleep(chan, 500);
1885
1886         /* AgentLogin() exit */
1887         if (!callbackmode) {
1888                 return -1;
1889         }
1890         /* AgentCallbackLogin() exit*/
1891         else {
1892                 /* Set variables */
1893                 if (login_state > 0) {
1894                         pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1895                         if (login_state==1) {
1896                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1897                                 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1898                         }
1899                         else {
1900                                 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1901                         }
1902                 }
1903                 else {
1904                         pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1905                 }
1906                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1907                         return 0;
1908                 /* Do we need to play agent-goodbye now that we will be hanging up? */
1909                 if (play_announcement==1) {
1910                         if (!res)
1911                                 res = ast_safe_sleep(chan, 1000);
1912                         res = ast_streamfile(chan, agent_goodbye, chan->language);
1913                         if (!res)
1914                                 res = ast_waitstream(chan, "");
1915                         if (!res)
1916                                 res = ast_safe_sleep(chan, 1000);
1917                 }
1918         }
1919         /* We should never get here if next priority exists when in callbackmode */
1920         return -1;
1921 }
1922
1923 static int login_exec(struct ast_channel *chan, void *data)
1924 {
1925         return __login_exec(chan, data, 0);
1926 }
1927
1928 static int callback_exec(struct ast_channel *chan, void *data)
1929 {
1930         return __login_exec(chan, data, 1);
1931 }
1932
1933 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1934 {
1935         int exitifnoagentid = 0;
1936         int nowarnings = 0;
1937         int changeoutgoing = 0;
1938         int res = 0;
1939         char agent[AST_MAX_AGENT], *tmp;
1940
1941         if (data) {
1942                 if (strchr(data, 'd'))
1943                         exitifnoagentid = 1;
1944                 if (strchr(data, 'n'))
1945                         nowarnings = 1;
1946                 if (strchr(data, 'c'))
1947                         changeoutgoing = 1;
1948         }
1949         if (chan->cid.cid_num) {
1950                 char agentvar[AST_MAX_BUF];
1951                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1952                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1953                         struct agent_pvt *p = agents;
1954                         strncpy(agent, tmp, sizeof(agent) - 1);
1955                         ast_mutex_lock(&agentlock);
1956                         while (p) {
1957                                 if (!strcasecmp(p->agent, tmp)) {
1958                                         if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1959                                         __agent_start_monitoring(chan, p, 1);
1960                                         break;
1961                                 }
1962                                 p = p->next;
1963                         }
1964                         ast_mutex_unlock(&agentlock);
1965                         
1966                 } else {
1967                         res = -1;
1968                         if (!nowarnings)
1969                                 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);
1970                 }
1971         } else {
1972                 res = -1;
1973                 if (!nowarnings)
1974                         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");
1975         }
1976         /* check if there is n + 101 priority */
1977         if (res) {
1978                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1979                         chan->priority+=100;
1980                         if (option_verbose > 2)
1981                                 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1982                }
1983                 else if (exitifnoagentid)
1984                         return res;
1985         }
1986         return 0;
1987 }
1988
1989 /* Dump AgentCallbackLogin agents to the database for persistence
1990  */
1991
1992 static void dump_agents(void)
1993 {
1994         struct agent_pvt *cur_agent = NULL;
1995
1996         for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
1997                 if (cur_agent->chan)
1998                         continue;
1999
2000                 if (!ast_strlen_zero(cur_agent->loginchan)) {
2001                         if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan))
2002                                 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2003                         else if (option_debug)
2004                                 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2005                 } else {
2006                         /* Delete -  no agent or there is an error */
2007                         ast_db_del(pa_family, cur_agent->agent);
2008                 }
2009         }
2010 }
2011
2012 /* Reload the persistent agents from astdb */
2013 static void reload_agents(void)
2014 {
2015         char *agent_num;
2016         struct ast_db_entry *db_tree;
2017         struct ast_db_entry *entry;
2018         struct agent_pvt *cur_agent;
2019         char agent_data[80];
2020
2021         db_tree = ast_db_gettree(pa_family, NULL);
2022
2023         ast_mutex_lock(&agentlock);
2024         for (entry = db_tree; entry; entry = entry->next) {
2025                 agent_num = db_tree->key + strlen(pa_family) + 2;
2026                 cur_agent = agents;
2027                 while (cur_agent) {
2028                         ast_mutex_lock(&cur_agent->lock);
2029                         if (strcmp(agent_num, cur_agent->agent) == 0)
2030                                 break;
2031                         ast_mutex_unlock(&cur_agent->lock);
2032                         cur_agent = cur_agent->next;
2033                 }
2034                 if (!cur_agent) {
2035                         ast_db_del(pa_family, agent_num);
2036                         continue;
2037                 } else
2038                         ast_mutex_unlock(&cur_agent->lock);
2039                 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2040                         if (option_debug)
2041                                 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2042                         strncpy(cur_agent->loginchan, agent_data, sizeof(cur_agent->loginchan)-1);
2043                         if (cur_agent->loginstart == 0)
2044                                 time(&cur_agent->loginstart);
2045                         ast_device_state_changed("Agent/%s", cur_agent->agent); 
2046                 }
2047         }
2048         ast_mutex_unlock(&agentlock);
2049         if (db_tree) {
2050                 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2051                 ast_db_freetree(db_tree);
2052         }
2053 }
2054
2055
2056 /*--- agent_devicestate: Part of PBX channel interface ---*/
2057 static int agent_devicestate(void *data)
2058 {
2059         struct agent_pvt *p;
2060         char *s;
2061         ast_group_t groupmatch;
2062         int groupoff;
2063         int waitforagent=0;
2064         int res = AST_DEVICE_INVALID;
2065         
2066         s = data;
2067         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2068                 groupmatch = (1 << groupoff);
2069         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2070                 groupmatch = (1 << groupoff);
2071                 waitforagent = 1;
2072         } else {
2073                 groupmatch = 0;
2074         }
2075
2076         /* Check actual logged in agents first */
2077         ast_mutex_lock(&agentlock);
2078         p = agents;
2079         while(p) {
2080                 ast_mutex_lock(&p->lock);
2081                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2082                         if (p->owner) {
2083                                 if (res != AST_DEVICE_INUSE)
2084                                         res = AST_DEVICE_BUSY;
2085                         } else {
2086                                 if (res == AST_DEVICE_BUSY)
2087                                         res = AST_DEVICE_INUSE;
2088                                 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2089                                         if (res == AST_DEVICE_INVALID)
2090                                                 res = AST_DEVICE_UNKNOWN;
2091                                 } else if (res == AST_DEVICE_INVALID)   
2092                                         res = AST_DEVICE_UNAVAILABLE;
2093                         }
2094                         if (!strcmp(data, p->agent)) {
2095                                 ast_mutex_unlock(&p->lock);
2096                                 break;
2097                         }
2098                 }
2099                 ast_mutex_unlock(&p->lock);
2100                 p = p->next;
2101         }
2102         ast_mutex_unlock(&agentlock);
2103         return res;
2104 }
2105
2106 /*--- load_module: Initialize channel module ---*/
2107 int load_module()
2108 {
2109         /* Make sure we can register our agent channel type */
2110         if (ast_channel_register(&agent_tech)) {
2111                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2112                 return -1;
2113         }
2114         /* Dialplan applications */
2115         ast_register_application(app, login_exec, synopsis, descrip);
2116         ast_register_application(app2, callback_exec, synopsis2, descrip2);
2117         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2118         /* Manager command */
2119         ast_manager_register2("Agents", 0, action_agents, "Lists agents and their status", mandescr_agents);
2120         /* CLI Application */
2121         ast_cli_register(&cli_show_agents);
2122         ast_cli_register(&cli_agent_logoff);
2123         /* Read in the config */
2124         read_agent_config();
2125         if (persistent_agents)
2126                 reload_agents();
2127         return 0;
2128 }
2129
2130 int reload()
2131 {
2132         read_agent_config();
2133         if (persistent_agents)
2134                 reload_agents();
2135         return 0;
2136 }
2137
2138 int unload_module()
2139 {
2140         struct agent_pvt *p;
2141         /* First, take us out of the channel loop */
2142         /* Unregister CLI application */
2143         ast_cli_unregister(&cli_show_agents);
2144         ast_cli_unregister(&cli_agent_logoff);
2145         /* Unregister dialplan applications */
2146         ast_unregister_application(app);
2147         ast_unregister_application(app2);
2148         ast_unregister_application(app3);
2149         /* Unregister manager command */
2150         ast_manager_unregister("Agents");
2151         /* Unregister channel */
2152         ast_channel_unregister(&agent_tech);
2153         if (!ast_mutex_lock(&agentlock)) {
2154                 /* Hangup all interfaces if they have an owner */
2155                 p = agents;
2156                 while(p) {
2157                         if (p->owner)
2158                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2159                         p = p->next;
2160                 }
2161                 agents = NULL;
2162                 ast_mutex_unlock(&agentlock);
2163         } else {
2164                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2165                 return -1;
2166         }               
2167         return 0;
2168 }
2169
2170 int usecount()
2171 {
2172         int res;
2173         ast_mutex_lock(&usecnt_lock);
2174         res = usecnt;
2175         ast_mutex_unlock(&usecnt_lock);
2176         return res;
2177 }
2178
2179 char *key()
2180 {
2181         return ASTERISK_GPL_KEY;
2182 }
2183
2184 char *description()
2185 {
2186         return (char *) desc;
2187 }
2188