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