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