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