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