f91c6324b8523cbef4a4dd24d6246f0c2975c97e
[asterisk/asterisk.git] / channels / chan_agent.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Implementation of Session Initiation Protocol
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
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 <pthread.h>
16 #include <string.h>
17 #include <asterisk/lock.h>
18 #include <asterisk/channel.h>
19 #include <asterisk/channel_pvt.h>
20 #include <asterisk/config.h>
21 #include <asterisk/logger.h>
22 #include <asterisk/module.h>
23 #include <asterisk/pbx.h>
24 #include <asterisk/options.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/sched.h>
27 #include <asterisk/io.h>
28 #include <asterisk/rtp.h>
29 #include <asterisk/acl.h>
30 #include <asterisk/callerid.h>
31 #include <asterisk/file.h>
32 #include <asterisk/cli.h>
33 #include <asterisk/app.h>
34 #include <asterisk/musiconhold.h>
35 #include <asterisk/manager.h>
36 #include <asterisk/parking.h>
37 #include <asterisk/utils.h>
38 #include <sys/socket.h>
39 #include <errno.h>
40 #include <unistd.h>
41 #include <stdlib.h>
42 #include <fcntl.h>
43 #include <netdb.h>
44 #include <arpa/inet.h>
45 #include <sys/signal.h>
46
47 static char *desc = "Agent Proxy Channel";
48 static char *type = "Agent";
49 static char *tdesc = "Call Agent Proxy Channel";
50 static char *config = "agents.conf";
51
52 static char *app = "AgentLogin";
53 static char *app2 = "AgentCallbackLogin";
54 static char *app3 = "AgentMonitorOutgoing";
55
56 static char *synopsis = "Call agent login";
57 static char *synopsis2 = "Call agent callback login";
58 static char *synopsis3 = "Record agent's outgoing call";
59
60 static char *descrip =
61 "  AgentLogin([AgentNo][|options]):\n"
62 "Asks the agent to login to the system.  Always returns -1.  While\n"
63 "logged in, the agent can receive calls and will hear a 'beep'\n"
64 "when a new call comes in.  The agent can dump the call by pressing\n"
65 "the star key.\n"
66 "The option string may contain zero or more of the following characters:\n"
67 "      's' -- silent login - do not announce the login ok segment\n";
68
69 static char *descrip2 =
70 "  AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
71 "Asks the agent to login to the system with callback.  Always returns -1.\n"
72 "The agent's callback extension is called (optionally with the specified\n"
73 "context. \n";
74
75 static char *descrip3 =
76 "  AgentMonitorOutgoing([options]):\n"
77 "Tries to figure out the id of the agent who is placing outgoing call based on comparision of the callerid of the current interface and the global variable placed by the AgentCallbackLogin application. That's why it should be used only with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent instead of Monitor application. That have to be configured in the agents.conf file. Normally the app returns 0 unless the options are passed. Also if the callerid or the agentid are not specified it'll look for n+101 priority. The options are:\n"
78 "       'd' - make the app return -1 if there is an error condition and there is no extension n+101\n"
79 "       'n' - don't generate the warnings when there is no callerid or the agentid is not known. It's handy if you want to have one context for agent and non-agent calls.\n";
80
81 static char moh[80] = "default";
82
83 #define AST_MAX_AGENT   80              /* Agent ID or Password max length */
84 #define AST_MAX_BUF     256
85
86 static int capability = -1;
87
88 static unsigned int group;
89 static int autologoff;
90 static int wrapuptime;
91 static int ackcall;
92
93 static int usecnt =0;
94 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
95
96 /* Protect the interface list (of sip_pvt's) */
97 AST_MUTEX_DEFINE_STATIC(agentlock);
98
99 static int recordagentcalls = 0;
100 static char recordformat[AST_MAX_BUF];
101 static char recordformatext[AST_MAX_BUF];
102 static int createlink = 0;
103 static char urlprefix[AST_MAX_BUF];
104 static char savecallsin[AST_MAX_BUF];
105 static int updatecdr = 0;
106
107 #define GETAGENTBYCALLERID      "AGENTBYCALLERID"
108
109 static struct agent_pvt {
110         ast_mutex_t lock;                               /* Channel private lock */
111         int dead;                                                       /* Poised for destruction? */
112         int pending;                                            /* Not a real agent -- just pending a match */
113         int abouttograb;                                        /* About to grab */
114         int autologoff;                                 /* Auto timeout time */
115         int ackcall;                                    /* ackcall */
116         time_t loginstart;                                      /* When agent first logged in (0 when logged off) */
117         time_t start;                                           /* When call started */
118         struct timeval lastdisc;                        /* When last disconnected */
119         int wrapuptime;                                         /* Wrapup time in ms */
120         unsigned int group;                                     /* Group memberships */
121         int acknowledged;                                       /* Acknowledged */
122         char moh[80];                                           /* Which music on hold */
123         char agent[AST_MAX_AGENT];                      /* Agent ID */
124         char password[AST_MAX_AGENT];           /* Password for Agent login */
125         char name[AST_MAX_AGENT];
126         ast_mutex_t app_lock;                   /* Synchronization between owning applications */
127         volatile pthread_t owning_app;          /* Owning application thread id */
128         volatile int app_sleep_cond;            /* Sleep condition for the login app */
129         struct ast_channel *owner;                      /* Agent */
130         char loginchan[80];
131         struct ast_channel *chan;                       /* Channel we use */
132         struct agent_pvt *next;                         /* Agent */
133 } *agents = NULL;
134
135 #define CHECK_FORMATS(ast, p) do { \
136         if (p->chan) {\
137                 if (ast->nativeformats != p->chan->nativeformats) { \
138                         ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
139                         /* Native formats changed, reset things */ \
140                         ast->nativeformats = p->chan->nativeformats; \
141                         ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
142                         ast_set_read_format(ast, ast->readformat); \
143                         ast_set_write_format(ast, ast->writeformat); \
144                 } \
145                 if (p->chan->readformat != ast->pvt->rawreadformat)  \
146                         ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
147                 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
148                         ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
149         } \
150 } while(0)
151
152 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
153    properly for a timingfd XXX This might need more work if agents were logged in as agents or other
154    totally impractical combinations XXX */
155
156 #define CLEANUP(ast, p) do { \
157         int x; \
158         if (p->chan) { \
159                 for (x=0;x<AST_MAX_FDS;x++) {\
160                         if (x != AST_MAX_FDS - 2) \
161                                 ast->fds[x] = p->chan->fds[x]; \
162                 } \
163                 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
164         } \
165 } while(0)
166
167
168 static void agent_unlink(struct agent_pvt *agent)
169 {
170         struct agent_pvt *p, *prev;
171         prev = NULL;
172         p = agents;
173         while(p) {
174                 if (p == agent) {
175                         if (prev)
176                                 prev->next = agent->next;
177                         else
178                                 agents = agent->next;
179                         break;
180                 }
181                 prev = p;
182                 p = p->next;
183         }
184 }
185
186 static struct agent_pvt *add_agent(char *agent, int pending)
187 {
188         char tmp[AST_MAX_BUF];
189         char *password=NULL, *name=NULL;
190         struct agent_pvt *p, *prev;
191         
192         strncpy(tmp, agent, sizeof(tmp));
193         if ((password = strchr(tmp, ','))) {
194                 *password = '\0';
195                 password++;
196                 while (*password < 33) password++;
197         }
198         if (password && (name = strchr(password, ','))) {
199                 *name = '\0';
200                 name++;
201                 while (*name < 33) name++; 
202         }
203         prev=NULL;
204         p = agents;
205         while(p) {
206                 if (!pending && !strcmp(p->agent, tmp))
207                         break;
208                 prev = p;
209                 p = p->next;
210         }
211         if (!p) {
212                 p = malloc(sizeof(struct agent_pvt));
213                 if (p) {
214                         memset(p, 0, sizeof(struct agent_pvt));
215                         strncpy(p->agent, tmp, sizeof(p->agent) -1);
216                         ast_mutex_init( &p->lock );
217                         ast_mutex_init( &p->app_lock );
218                         p->owning_app = (pthread_t) -1;
219                         p->app_sleep_cond = 1;
220                         p->group = group;
221                         p->pending = pending;
222                         p->next = NULL;
223                         if (prev)
224                                 prev->next = p;
225                         else
226                                 agents = p;
227                         
228                 }
229         }
230         if (!p)
231                 return NULL;
232         strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
233         strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
234         strncpy(p->moh, moh, sizeof(p->moh) - 1);
235         p->ackcall = ackcall;
236         p->autologoff = autologoff;
237         p->wrapuptime = wrapuptime;
238         if (pending)
239                 p->dead = 1;
240         else
241                 p->dead = 0;
242         return p;
243 }
244
245 static int agent_cleanup(struct agent_pvt *p)
246 {
247         struct ast_channel *chan = p->owner;
248         p->owner = NULL;
249         chan->pvt->pvt = NULL;
250         p->app_sleep_cond = 1;
251         /* Release ownership of the agent to other threads (presumably running the login app). */
252         ast_mutex_unlock(&p->app_lock);
253         if (chan)
254                 ast_channel_free(chan);
255         if (p->dead)
256                 free(p);
257         return 0;
258 }
259
260 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
261
262 static int agent_answer(struct ast_channel *ast)
263 {
264         ast_log(LOG_WARNING, "Huh?  Agent is being asked to answer?\n");
265         return -1;
266 }
267
268 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
269 {
270         char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
271         char filename[AST_MAX_BUF];
272         int res = -1;
273         if (!p)
274                 return -1;
275         if (!ast->monitor) {
276                 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
277                 /* substitute . for - */
278                 if ((pointer = strchr(filename, '.')))
279                         *pointer = '-';
280                 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
281                 ast_monitor_start(ast, recordformat, tmp, needlock);
282                 ast_monitor_setjoinfiles(ast, 1);
283                 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
284 #if 0
285                 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
286 #endif
287                 if (!ast->cdr)
288                         ast->cdr = ast_cdr_alloc();
289                 ast_cdr_setuserfield(ast, tmp2);
290                 res = 0;
291         } else
292                 ast_log(LOG_ERROR, "Recording already started on that call.\n");
293         return res;
294 }
295
296 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
297 {
298         return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
299 }
300
301 static struct ast_frame  *agent_read(struct ast_channel *ast)
302 {
303         struct agent_pvt *p = ast->pvt->pvt;
304         struct ast_frame *f = NULL;
305         static struct ast_frame null_frame = { AST_FRAME_NULL, };
306         static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
307         ast_mutex_lock(&p->lock); 
308         CHECK_FORMATS(ast, p);
309         if (p->chan) {
310                 p->chan->exception = ast->exception;
311                 if (ast->fdno == AST_MAX_FDS - 3)
312                         p->chan->fdno = AST_MAX_FDS - 2;
313                 else
314                         p->chan->fdno = ast->fdno;
315                 f = ast_read(p->chan);
316         } else
317                 f = &null_frame;
318         if (!f) {
319                 /* If there's a channel, hang it up  (if it's on a callback) make it NULL */
320                 if (p->chan) {
321                         /* Note that we don't hangup if it's not a callback because Asterisk will do it
322                            for us when the PBX instance that called login finishes */
323                         if (!ast_strlen_zero(p->loginchan))
324                                 ast_hangup(p->chan);
325                         p->chan = NULL;
326                         p->acknowledged = 0;
327                 }
328         }
329         if (f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
330 /* TC */
331                 if (p->ackcall) {
332                         if (option_verbose > 2)
333                                 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
334                         /* Don't pass answer along */
335                         ast_frfree(f);
336                         f = &null_frame;
337                 }
338         else {
339                         p->acknowledged = 1;
340                         f = &answer_frame;
341         }
342         }
343         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
344                 if (!p->acknowledged) {
345                         if (option_verbose > 2)
346                                 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
347                         p->acknowledged = 1;
348                         ast_frfree(f);
349                         f = &answer_frame;
350                 }
351         }
352         if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
353                 /* * terminates call */
354                 ast_frfree(f);
355                 f = NULL;
356         }
357         CLEANUP(ast,p);
358         ast_mutex_unlock(&p->lock);
359         if (recordagentcalls && f == &answer_frame)
360                 agent_start_monitoring(ast,0);
361         return f;
362 }
363
364 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
365 {
366         struct agent_pvt *p = ast->pvt->pvt;
367         int res = -1;
368         CHECK_FORMATS(ast, p);
369         ast_mutex_lock(&p->lock);
370         if (p->chan) {
371                 if ((f->frametype != AST_FRAME_VOICE) ||
372                         (f->subclass == p->chan->writeformat)) {
373                         res = ast_write(p->chan, f);
374                 } else {
375                         ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
376                         res = 0;
377                 }
378         } else
379                 res = 0;
380         CLEANUP(ast, p);
381         ast_mutex_unlock(&p->lock);
382         return res;
383 }
384
385 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
386 {
387         struct agent_pvt *p = newchan->pvt->pvt;
388         ast_mutex_lock(&p->lock);
389         if (p->owner != oldchan) {
390                 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
391                 ast_mutex_unlock(&p->lock);
392                 return -1;
393         }
394         p->owner = newchan;
395         ast_mutex_unlock(&p->lock);
396         return 0;
397 }
398
399 static int agent_indicate(struct ast_channel *ast, int condition)
400 {
401         struct agent_pvt *p = ast->pvt->pvt;
402         int res = -1;
403         ast_mutex_lock(&p->lock);
404         if (p->chan)
405                 res = ast_indicate(p->chan, condition);
406         else
407                 res = 0;
408         ast_mutex_unlock(&p->lock);
409         return res;
410 }
411
412 static int agent_digit(struct ast_channel *ast, char digit)
413 {
414         struct agent_pvt *p = ast->pvt->pvt;
415         int res = -1;
416         ast_mutex_lock(&p->lock);
417         if (p->chan)
418                 res = p->chan->pvt->send_digit(p->chan, digit);
419         else
420                 res = 0;
421         ast_mutex_unlock(&p->lock);
422         return res;
423 }
424
425 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
426 {
427         struct agent_pvt *p = ast->pvt->pvt;
428         int res = -1;
429         ast_mutex_lock(&p->lock);
430         p->acknowledged = 0;
431         if (!p->chan) {
432                 if (p->pending) {
433                         ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
434                         ast_setstate(ast, AST_STATE_DIALING);
435                         res = 0;
436                 } else {
437                         ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call...  what are the odds of that?\n");
438                         res = -1;
439                 }
440                 ast_mutex_unlock(&p->lock);
441                 return res;
442         } else if (!ast_strlen_zero(p->loginchan)) {
443                 time(&p->start);
444                 /* Call on this agent */
445                 if (option_verbose > 2)
446                         ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
447                 if (p->chan->callerid)
448                         free(p->chan->callerid);
449                 if (ast->callerid)
450                         p->chan->callerid = strdup(ast->callerid);
451                 else
452                         p->chan->callerid = NULL;
453                 res = ast_call(p->chan, p->loginchan, 0);
454                 CLEANUP(ast,p);
455                 ast_mutex_unlock(&p->lock);
456                 return res;
457         }
458         ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
459         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
460         res = ast_streamfile(p->chan, "beep", p->chan->language);
461         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
462         if (!res) {
463                 res = ast_waitstream(p->chan, "");
464                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
465         }
466         if (!res) {
467                 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
468                 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
469                 if (res)
470                         ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
471         } else {
472                 // Agent hung-up
473                 p->chan = NULL;
474         }
475
476         if (!res) {
477                 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
478                 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
479                 if (res)
480                         ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
481         }
482         if( !res )
483         {
484                 /* Call is immediately up, or might need ack */
485                 if (p->ackcall > 1)
486                         ast_setstate(ast, AST_STATE_RINGING);
487                 else {
488                         ast_setstate(ast, AST_STATE_UP);
489                         if (recordagentcalls)
490                                 agent_start_monitoring(ast,0);
491                         p->acknowledged = 1;
492                 }
493                 res = 0;
494         }
495         CLEANUP(ast,p);
496         ast_mutex_unlock(&p->lock);
497         return res;
498 }
499
500 static int agent_hangup(struct ast_channel *ast)
501 {
502         struct agent_pvt *p = ast->pvt->pvt;
503         int howlong = 0;
504         ast_mutex_lock(&p->lock);
505         p->owner = NULL;
506         ast->pvt->pvt = NULL;
507         p->app_sleep_cond = 1;
508         p->acknowledged = 0;
509         if (p->start && (ast->_state != AST_STATE_UP))
510                 howlong = time(NULL) - p->start;
511         time(&p->start);
512         if (p->chan) {
513                 /* If they're dead, go ahead and hang up on the agent now */
514                 if (!ast_strlen_zero(p->loginchan)) {
515                         if (p->chan) {
516                                 /* Recognize the hangup and pass it along immediately */
517                                 ast_hangup(p->chan);
518                                 p->chan = NULL;
519                         }
520                         ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
521                         if (howlong  && p->autologoff && (howlong > p->autologoff)) {
522                                 char agent[AST_MAX_AGENT] = "";
523                                 long logintime = time(NULL) - p->loginstart;
524                                 p->loginstart = 0;
525                                 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
526                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
527                                         "Agent: %s\r\n"
528                                         "Loginchan: %s\r\n"
529                                         "Logintime: %ld\r\n"
530                                         "Reason: Autologoff\r\n"
531                                         "Uniqueid: %s\r\n",
532                                         p->agent, p->loginchan, logintime, ast->uniqueid);
533                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
534                                 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
535                                 strcpy(p->loginchan, "");
536                         }
537                 } else if (p->dead) {
538                         ast_mutex_lock(&p->chan->lock);
539                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
540                         ast_mutex_unlock(&p->chan->lock);
541                 } else {
542                         ast_mutex_lock(&p->chan->lock);
543                         ast_moh_start(p->chan, p->moh);
544                         ast_mutex_unlock(&p->chan->lock);
545                 }
546         }
547 #if 0
548                 ast_mutex_unlock(&p->lock);
549                 /* Release ownership of the agent to other threads (presumably running the login app). */
550                 ast_mutex_unlock(&p->app_lock);
551         } else if (p->dead) {
552                 /* Go ahead and lose it */
553                 ast_mutex_unlock(&p->lock);
554                 /* Release ownership of the agent to other threads (presumably running the login app). */
555                 ast_mutex_unlock(&p->app_lock);
556         } else {
557                 ast_mutex_unlock(&p->lock);
558                 /* Release ownership of the agent to other threads (presumably running the login app). */
559                 ast_mutex_unlock(&p->app_lock);
560         }
561 #endif  
562         ast_mutex_unlock(&p->lock);
563
564         if (p->pending) {
565                 ast_mutex_lock(&agentlock);
566                 agent_unlink(p);
567                 ast_mutex_unlock(&agentlock);
568         }
569         if (p->abouttograb) {
570                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
571                    kill it later */
572                 p->abouttograb = 0;
573         } else if (p->dead) {
574                 free(p);
575         } else {
576                 if (p->chan) {
577                         /* Not dead -- check availability now */
578                         ast_mutex_lock(&p->lock);
579                         /* Store last disconnect time */
580                         gettimeofday(&p->lastdisc, NULL);
581                         ast_mutex_unlock(&p->lock);
582                 }
583                 /* Release ownership of the agent to other threads (presumably running the login app). */
584                 ast_mutex_unlock(&p->app_lock);
585         }
586         return 0;
587 }
588
589 static int agent_cont_sleep( void *data )
590 {
591         struct agent_pvt *p;
592         struct timeval tv;
593         int res;
594
595         p = (struct agent_pvt *)data;
596
597         ast_mutex_lock(&p->lock);
598         res = p->app_sleep_cond;
599         if (p->lastdisc.tv_sec) {
600                 gettimeofday(&tv, NULL);
601                 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
602                         (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) 
603                         res = 1;
604         }
605         ast_mutex_unlock(&p->lock);
606 #if 0
607         if( !res )
608                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
609 #endif          
610         return res;
611 }
612
613 static int agent_ack_sleep( void *data )
614 {
615         struct agent_pvt *p;
616         int res=0;
617         int to = 1000;
618         struct ast_frame *f;
619
620         /* Wait a second and look for something */
621
622         p = (struct agent_pvt *)data;
623         if (p->chan) {
624                 for(;;) {
625                         to = ast_waitfor(p->chan, to);
626                         if (to < 0) {
627                                 res = -1;
628                                 break;
629                         }
630                         if (!to) {
631                                 res = 0;
632                                 break;
633                         }
634                         f = ast_read(p->chan);
635                         if (!f) {
636                                 res = -1;
637                                 break;
638                         }
639                         if (f->frametype == AST_FRAME_DTMF)
640                                 res = f->subclass;
641                         else
642                                 res = 0;
643                         ast_frfree(f);
644                         ast_mutex_lock(&p->lock);
645                         if (!p->app_sleep_cond) {
646                                 ast_mutex_unlock(&p->lock);
647                                 res = 0;
648                                 break;
649                         } else if (res == '#') {
650                                 ast_mutex_unlock(&p->lock);
651                                 res = 1;
652                                 break;
653                         }
654                         ast_mutex_unlock(&p->lock);
655                         res = 0;
656                 }
657         } else
658                 res = -1;
659         return res;
660 }
661
662 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
663 {
664         struct ast_channel *tmp;
665         struct ast_frame null_frame = { AST_FRAME_NULL };
666 #if 0
667         if (!p->chan) {
668                 ast_log(LOG_WARNING, "No channel? :(\n");
669                 return NULL;
670         }
671 #endif  
672         tmp = ast_channel_alloc(0);
673         if (tmp) {
674                 if (p->chan) {
675                         tmp->nativeformats = p->chan->nativeformats;
676                         tmp->writeformat = p->chan->writeformat;
677                         tmp->pvt->rawwriteformat = p->chan->writeformat;
678                         tmp->readformat = p->chan->readformat;
679                         tmp->pvt->rawreadformat = p->chan->readformat;
680                         strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
681                         strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
682                         strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
683                 } else {
684                         tmp->nativeformats = AST_FORMAT_SLINEAR;
685                         tmp->writeformat = AST_FORMAT_SLINEAR;
686                         tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
687                         tmp->readformat = AST_FORMAT_SLINEAR;
688                         tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
689                 }
690                 if (p->pending)
691                         snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
692                 else
693                         snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
694                 tmp->type = type;
695                 ast_setstate(tmp, state);
696                 tmp->pvt->pvt = p;
697                 tmp->pvt->send_digit = agent_digit;
698                 tmp->pvt->call = agent_call;
699                 tmp->pvt->hangup = agent_hangup;
700                 tmp->pvt->answer = agent_answer;
701                 tmp->pvt->read = agent_read;
702                 tmp->pvt->write = agent_write;
703                 tmp->pvt->exception = agent_read;
704                 tmp->pvt->indicate = agent_indicate;
705                 tmp->pvt->fixup = agent_fixup;
706                 p->owner = tmp;
707                 ast_mutex_lock(&usecnt_lock);
708                 usecnt++;
709                 ast_mutex_unlock(&usecnt_lock);
710                 ast_update_use_count();
711                 tmp->priority = 1;
712                 /* Wake up and wait for other applications (by definition the login app)
713                  * to release this channel). Takes ownership of the agent channel
714                  * to this thread only.
715                  * For signalling the other thread, ast_queue_frame is used until we
716                  * can safely use signals for this purpose. The pselect() needs to be
717                  * implemented in the kernel for this.
718                  */
719                 p->app_sleep_cond = 0;
720                 if( ast_mutex_trylock(&p->app_lock) )
721                 {
722                         if (p->chan) {
723                                 ast_queue_frame(p->chan, &null_frame);
724                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
725                                 ast_mutex_lock(&p->app_lock);
726                                 ast_mutex_lock(&p->lock);
727                         }
728                         if( !p->chan )
729                         {
730                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
731                                 p->owner = NULL;
732                                 tmp->pvt->pvt = NULL;
733                                 p->app_sleep_cond = 1;
734                                 ast_channel_free( tmp );
735                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
736                                 ast_mutex_unlock(&p->app_lock);
737                                 return NULL;
738                         }
739                 }
740                 p->owning_app = pthread_self();
741                 /* After the above step, there should not be any blockers. */
742                 if (p->chan) {
743                         if (p->chan->blocking) {
744                                 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
745                                 CRASH;
746                         }
747                         ast_moh_stop(p->chan);
748                 }
749         } else
750                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
751         return tmp;
752 }
753
754
755 static int read_agent_config(void)
756 {
757         struct ast_config *cfg;
758         struct ast_variable *v;
759         struct agent_pvt *p, *pl, *pn;
760         group = 0;
761         autologoff = 0;
762         wrapuptime = 0;
763         ackcall = 1;
764         cfg = ast_load(config);
765         if (!cfg) {
766                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
767                 return 0;
768         }
769         ast_mutex_lock(&agentlock);
770         p = agents;
771         while(p) {
772                 p->dead = 1;
773                 p = p->next;
774         }
775         strcpy(moh, "default");
776         /* set the default recording values */
777         recordagentcalls = 0;
778         createlink = 0;
779         strcpy(recordformat, "wav");
780         strcpy(recordformatext, "wav");
781         strcpy(urlprefix, "");
782         strcpy(savecallsin, "");
783
784         v = ast_variable_browse(cfg, "agents");
785         while(v) {
786                 /* Create the interface list */
787                 if (!strcasecmp(v->name, "agent")) {
788                         add_agent(v->value, 0);
789                 } else if (!strcasecmp(v->name, "group")) {
790                         group = ast_get_group(v->value);
791                 } else if (!strcasecmp(v->name, "autologoff")) {
792                         autologoff = atoi(v->value);
793                         if (autologoff < 0)
794                                 autologoff = 0;
795                 } else if (!strcasecmp(v->name, "ackcall")) {
796                         if (!strcasecmp(v->value, "always"))
797                                 ackcall = 2;
798                         else if (ast_true(v->value))
799                 ackcall = 1;
800                         else
801                                 ackcall = 0;
802                 } else if (!strcasecmp(v->name, "wrapuptime")) {
803                         wrapuptime = atoi(v->value);
804                         if (wrapuptime < 0)
805                                 wrapuptime = 0;
806                 } else if (!strcasecmp(v->name, "musiconhold")) {
807                         strncpy(moh, v->value, sizeof(moh) - 1);
808                 } else if (!strcasecmp(v->name, "updatecdr")) {
809                         updatecdr = ast_true(v->value);
810                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
811                         recordagentcalls = ast_true(v->value);
812                 } else if (!strcasecmp(v->name, "createlink")) {
813                         createlink = ast_true(v->value);
814                 } else if (!strcasecmp(v->name, "recordformat")) {
815                         strncpy(recordformat, v->value, sizeof(recordformat) - 1);
816                         if (!strcasecmp(v->value, "wav49"))
817                                 strcpy(recordformatext, "WAV");
818                         else
819                                 strncpy(recordformatext, v->value, sizeof(recordformat) - 1);
820                 } else if (!strcasecmp(v->name, "urlprefix")) {
821                         strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
822                         if (urlprefix[strlen(urlprefix) - 1] != '/')
823                                 strcat(urlprefix, "/");
824                 } else if (!strcasecmp(v->name, "savecallsin")) {
825                         if (v->value[0] == '/')
826                                 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
827                         else
828                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
829                         if (savecallsin[strlen(savecallsin) - 1] != '/')
830                                 strcat(savecallsin, "/");
831                 }
832                 v = v->next;
833         }
834         p = agents;
835         pl = NULL;
836         while(p) {
837                 pn = p->next;
838                 if (p->dead) {
839                         /* Unlink */
840                         if (pl)
841                                 pl->next = p->next;
842                         else
843                                 agents = p->next;
844                         /* Destroy if  appropriate */
845                         if (!p->owner) {
846                                 if (!p->chan) {
847                                         free(p);
848                                 } else {
849                                         /* Cause them to hang up */
850                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
851                                 }
852                         }
853                 } else
854                         pl = p;
855                 p = pn;
856         }
857         ast_mutex_unlock(&agentlock);
858         ast_destroy(cfg);
859         return 0;
860 }
861
862 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
863 {
864         struct ast_channel *chan=NULL, *parent=NULL;
865         struct agent_pvt *p;
866         int res;
867         ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
868         if (needlock)
869                 ast_mutex_lock(&agentlock);
870         p = agents;
871         while(p) {
872                 if (p == newlyavailable) {
873                         p = p->next;
874                         continue;
875                 }
876                 ast_mutex_lock(&p->lock);
877                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
878                         ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
879                         /* We found a pending call, time to merge */
880                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
881                         parent = p->owner;
882                         p->abouttograb = 1;
883                         ast_mutex_unlock(&p->lock);
884                         break;
885                 }
886                 ast_mutex_unlock(&p->lock);
887                 p = p->next;
888         }
889         if (needlock)
890                 ast_mutex_unlock(&agentlock);
891         if (parent && chan)  {
892                 if (newlyavailable->ackcall > 1) {
893                         /* Don't do beep here */
894                         res = 0;
895                 } else {
896                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
897                         res = ast_streamfile(newlyavailable->chan, "beep", newlyavailable->chan->language);
898                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
899                         if (!res) {
900                                 res = ast_waitstream(newlyavailable->chan, "");
901                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
902                         }
903                 }
904                 if (!res) {
905                         /* Note -- parent may have disappeared */
906                         if (p->abouttograb) {
907                                 newlyavailable->acknowledged = 1;
908                                 ast_setstate(parent, AST_STATE_UP);
909                                 ast_setstate(chan, AST_STATE_UP);
910                                 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
911                                 /* Go ahead and mark the channel as a zombie so that masquerade will
912                                    destroy it for us, and we need not call ast_hangup */
913                                 ast_mutex_lock(&parent->lock);
914                                 chan->zombie = 1;
915                                 ast_channel_masquerade(parent, chan);
916                                 ast_mutex_unlock(&parent->lock);
917                                 p->abouttograb = 0;
918                         } else {
919                                 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
920                                 agent_cleanup(newlyavailable);
921                         }
922                 } else {
923                         ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
924                         agent_cleanup(newlyavailable);
925                 }
926         }
927         return 0;
928 }
929
930 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
931 {
932         struct agent_pvt *p;
933         int res=0;
934         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
935         if (needlock)
936                 ast_mutex_lock(&agentlock);
937         p = agents;
938         while(p) {
939                 if (p == newlyavailable) {
940                         p = p->next;
941                         continue;
942                 }
943                 ast_mutex_lock(&p->lock);
944                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
945                         ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
946                         ast_mutex_unlock(&p->lock);
947                         break;
948                 }
949                 ast_mutex_unlock(&p->lock);
950                 p = p->next;
951         }
952         if (needlock)
953                 ast_mutex_unlock(&agentlock);
954         if (p) {
955                 ast_mutex_unlock(&newlyavailable->lock);
956                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
957                 res = ast_streamfile(newlyavailable->chan, "beep", newlyavailable->chan->language);
958                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
959                 if (!res) {
960                         res = ast_waitstream(newlyavailable->chan, "");
961                         ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
962                 }
963                 ast_mutex_lock(&newlyavailable->lock);
964         }
965         return res;
966 }
967
968 static struct ast_channel *agent_request(char *type, int format, void *data)
969 {
970         struct agent_pvt *p;
971         struct ast_channel *chan = NULL;
972         char *s;
973         unsigned int groupmatch;
974         int waitforagent=0;
975         int hasagent = 0;
976         s = data;
977         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
978                 groupmatch = (1 << groupmatch);
979         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
980                 groupmatch = (1 << groupmatch);
981                 waitforagent = 1;
982         } else {
983                 groupmatch = 0;
984         }
985
986         /* Check actual logged in agents first */
987         ast_mutex_lock(&agentlock);
988         p = agents;
989         while(p) {
990                 ast_mutex_lock(&p->lock);
991                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
992                                 ast_strlen_zero(p->loginchan)) {
993                         if (p->chan)
994                                 hasagent++;
995                         if (!p->lastdisc.tv_sec) {
996                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
997                                 if (!p->owner && p->chan) {
998                                         /* Fixed agent */
999                                         chan = agent_new(p, AST_STATE_DOWN);
1000                                 }
1001                                 if (chan) {
1002                                         ast_mutex_unlock(&p->lock);
1003                                         break;
1004                                 }
1005                         }
1006                 }
1007                 ast_mutex_unlock(&p->lock);
1008                 p = p->next;
1009         }
1010         if (!p) {
1011                 p = agents;
1012                 while(p) {
1013                         ast_mutex_lock(&p->lock);
1014                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1015                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1016                                         hasagent++;
1017                                 if (!p->lastdisc.tv_sec) {
1018                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1019                                         if (!p->owner && p->chan) {
1020                                                 /* Could still get a fixed agent */
1021                                                 chan = agent_new(p, AST_STATE_DOWN);
1022                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1023                                                 /* Adjustable agent */
1024                                                 p->chan = ast_request("Local", format, p->loginchan);
1025                                                 if (p->chan)
1026                                                         chan = agent_new(p, AST_STATE_DOWN);
1027                                         }
1028                                         if (chan) {
1029                                                 ast_mutex_unlock(&p->lock);
1030                                                 break;
1031                                         }
1032                                 }
1033                         }
1034                         ast_mutex_unlock(&p->lock);
1035                         p = p->next;
1036                 }
1037         }
1038
1039         if (!chan && waitforagent) {
1040                 /* No agent available -- but we're requesting to wait for one.
1041                    Allocate a place holder */
1042                 if (hasagent) {
1043                         ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1044                         p = add_agent(data, 1);
1045                         p->group = groupmatch;
1046                         chan = agent_new(p, AST_STATE_DOWN);
1047                         if (!chan) {
1048                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1049                         }
1050                 } else
1051                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1052         }
1053         ast_mutex_unlock(&agentlock);
1054         return chan;
1055 }
1056
1057 static int powerof(unsigned int v)
1058 {
1059         int x;
1060         for (x=0;x<32;x++) {
1061                 if (v & (1 << x)) return x;
1062         }
1063         return 0;
1064 }
1065
1066 static int agents_show(int fd, int argc, char **argv)
1067 {
1068         struct agent_pvt *p;
1069         char username[AST_MAX_BUF];
1070         char location[AST_MAX_BUF];
1071         char talkingto[AST_MAX_BUF];
1072         char moh[AST_MAX_BUF];
1073
1074         if (argc != 2)
1075                 return RESULT_SHOWUSAGE;
1076         ast_mutex_lock(&agentlock);
1077         p = agents;
1078         while(p) {
1079                 ast_mutex_lock(&p->lock);
1080                 if (p->pending) {
1081                         if (p->group)
1082                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1083                         else
1084                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1085                 } else {
1086                         if (!ast_strlen_zero(p->name))
1087                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1088                         else
1089                                 strcpy(username, "");
1090                         if (p->chan) {
1091                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1092                                 if (p->owner && p->owner->bridge) {
1093                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
1094                                 } else {
1095                                         strcpy(talkingto, " is idle");
1096                                 }
1097                         } else if (!ast_strlen_zero(p->loginchan)) {
1098                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1099                                 strcpy(talkingto, "");
1100                                 if (p->acknowledged)
1101                                         strcat(location, " (Confirmed)");
1102                         } else {
1103                                 strcpy(location, "not logged in");
1104                                 strcpy(talkingto, "");
1105                         }
1106                         if (!ast_strlen_zero(p->moh))
1107                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1108                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1109                                         username, location, talkingto, moh);
1110                 }
1111                 ast_mutex_unlock(&p->lock);
1112                 p = p->next;
1113         }
1114         ast_mutex_unlock(&agentlock);
1115         return RESULT_SUCCESS;
1116 }
1117
1118 static char show_agents_usage[] = 
1119 "Usage: show agents\n"
1120 "       Provides summary information on agents.\n";
1121
1122 static struct ast_cli_entry cli_show_agents = {
1123         { "show", "agents", NULL }, agents_show, 
1124         "Show status of agents", show_agents_usage, NULL };
1125
1126 STANDARD_LOCAL_USER;
1127 LOCAL_USER_DECL;
1128
1129 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1130 {
1131         int res=0;
1132         int tries = 0;
1133         struct agent_pvt *p;
1134         struct localuser *u;
1135         struct timeval tv;
1136         char user[AST_MAX_AGENT];
1137         char pass[AST_MAX_AGENT];
1138         char agent[AST_MAX_AGENT] = "";
1139         char xpass[AST_MAX_AGENT] = "";
1140         char *errmsg;
1141         char info[512];
1142         char *opt_user = NULL;
1143         char *options = NULL;
1144         char *context = NULL;
1145         char *exten = NULL;
1146         int play_announcement;
1147         char *filename = "agent-loginok";
1148         
1149         LOCAL_USER_ADD(u);
1150
1151         /* Parse the arguments XXX Check for failure XXX */
1152         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1153         opt_user = info;
1154         if( opt_user ) {
1155                 options = strchr(opt_user, '|');
1156                 if (options) {
1157                         *options = '\0';
1158                         options++;
1159                         if (callbackmode) {
1160                                 context = strchr(options, '@');
1161                                 if (context) {
1162                                         *context = '\0';
1163                                         context++;
1164                                 }
1165                                 exten = options;
1166                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1167                                 if (!*exten)
1168                                         exten = NULL;
1169                         }
1170                 }
1171         }
1172
1173         if (chan->_state != AST_STATE_UP)
1174                 res = ast_answer(chan);
1175         if (!res) {
1176                 if( opt_user && !ast_strlen_zero(opt_user))
1177                         strncpy( user, opt_user, AST_MAX_AGENT );
1178                 else
1179                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1180         }
1181         while (!res && (tries < 3)) {
1182                 /* Check for password */
1183                 ast_mutex_lock(&agentlock);
1184                 p = agents;
1185                 while(p) {
1186                         if (!strcmp(p->agent, user) && !p->pending)
1187                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1188                         p = p->next;
1189                 }
1190                 ast_mutex_unlock(&agentlock);
1191                 if (!res) {
1192                         if (!ast_strlen_zero(xpass))
1193                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1194                         else
1195                                 strcpy(pass, "");
1196                 }
1197                 errmsg = "agent-incorrect";
1198
1199 #if 0
1200                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1201 #endif          
1202
1203                 /* Check again for accuracy */
1204                 ast_mutex_lock(&agentlock);
1205                 p = agents;
1206                 while(p) {
1207                         ast_mutex_lock(&p->lock);
1208                         if (!strcmp(p->agent, user) &&
1209                                 !strcmp(p->password, pass) && !p->pending) {
1210                                         if (!p->chan) {
1211                                                 char last_loginchan[80] = "";
1212                                                 long logintime;
1213                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1214
1215                                                 if (callbackmode) {
1216                                                         char tmpchan[AST_MAX_BUF] = "";
1217                                                         int pos = 0;
1218                                                         /* Retrieve login chan */
1219                                                         for (;;) {
1220                                                                 if (exten) {
1221                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1222                                                                         res = 0;
1223                                                                 } else
1224                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1225                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1226                                                                                         1, NULL))
1227                                                                         break;
1228                                                                 if (exten) {
1229                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1230                                                                         exten = NULL;
1231                                                                         pos = 0;
1232                                                                 } else {
1233                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1234                                                                         if (!res)
1235                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1236                                                                         if (res > 0) {
1237                                                                                 tmpchan[0] = res;
1238                                                                                 tmpchan[1] = '\0';
1239                                                                                 pos = 1;
1240                                                                         } else {
1241                                                                                 tmpchan[0] = '\0';
1242                                                                                 pos = 0;
1243                                                                         }
1244                                                                 }
1245                                                         }
1246                                                         if (!res) {
1247                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1248                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1249                                                                 else {
1250                                                                         strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1251                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1252                                                                 }
1253                                                                 if (ast_strlen_zero(p->loginchan))
1254                                                                         filename = "agent-loggedoff";
1255                                                                 p->acknowledged = 0;
1256                                                                 /* store/clear the global variable that stores agentid based on the callerid */
1257                                                                 if (chan->callerid) {
1258                                                                         char agentvar[AST_MAX_BUF];
1259                                                                         snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->callerid);
1260                                                                         if (ast_strlen_zero(p->loginchan))
1261                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1262                                                                         else
1263                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1264                                                                 }
1265                                                                 if(updatecdr && chan->cdr)
1266                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1267
1268                                                         }
1269                                                 } else {
1270                                                         strcpy(p->loginchan, "");
1271                                                         p->acknowledged = 0;
1272                                                 }
1273                                                 play_announcement = 1;
1274                                                 if( options )
1275                                                         if( strchr( options, 's' ) )
1276                                                                 play_announcement = 0;
1277                                                 ast_mutex_unlock(&p->lock);
1278                                                 ast_mutex_unlock(&agentlock);
1279                                                 if( !res && play_announcement )
1280                                                         res = ast_streamfile(chan, filename, chan->language);
1281                                                 if (!res)
1282                                                         ast_waitstream(chan, "");
1283                                                 ast_mutex_lock(&agentlock);
1284                                                 ast_mutex_lock(&p->lock);
1285                                                 if (!res) {
1286                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1287                                                         if (res)
1288                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1289                                                 }
1290                                                 if (!res) {
1291                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1292                                                         if (res)
1293                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1294                                                 }
1295                                                 /* Check once more just in case */
1296                                                 if (p->chan)
1297                                                         res = -1;
1298                                                 if (callbackmode && !res) {
1299                                                         /* Just say goodbye and be done with it */
1300                                                         if (!ast_strlen_zero(p->loginchan)) {
1301                                                                 if (p->loginstart == 0)
1302                                                                         time(&p->loginstart);
1303                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1304                                                                         "Agent: %s\r\n"
1305                                                                         "Loginchan: %s\r\n"
1306                                                                         "Uniqueid: %s\r\n",
1307                                                                         p->agent, p->loginchan, chan->uniqueid);
1308                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1309                                                                 if (option_verbose > 2)
1310                                                                         ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1311                                                         } else {
1312                                                                 logintime = time(NULL) - p->loginstart;
1313                                                                 p->loginstart = 0;
1314                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1315                                                                         "Agent: %s\r\n"
1316                                                                         "Loginchan: %s\r\n"
1317                                                                         "Logintime: %ld\r\n"
1318                                                                         "Uniqueid: %s\r\n",
1319                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1320                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1321                                                                 if (option_verbose > 2)
1322                                                                         ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged out\n", p->agent);
1323                                                         }
1324                                                         ast_mutex_unlock(&agentlock);
1325                                                         if (!res)
1326                                                                 res = ast_safe_sleep(chan, 500);
1327                                                         res = ast_streamfile(chan, "vm-goodbye", chan->language);
1328                                                         if (!res)
1329                                                                 res = ast_waitstream(chan, "");
1330                                                         if (!res)
1331                                                                 res = ast_safe_sleep(chan, 1000);
1332                                                         ast_mutex_unlock(&p->lock);
1333                                                 } else if (!res) {
1334 #ifdef HONOR_MUSIC_CLASS
1335                                                         /* check if the moh class was changed with setmusiconhold */
1336                                                         if (*(chan->musicclass))
1337                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1338 #endif                                                          
1339                                                         ast_moh_start(chan, p->moh);
1340                                                         if (p->loginstart == 0)
1341                                                                 time(&p->loginstart);
1342                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1343                                                                 "Agent: %s\r\n"
1344                                                                 "Channel: %s\r\n"
1345                                                                 "Uniqueid: %s\r\n",
1346                                                                 p->agent, chan->name, chan->uniqueid);
1347                                                         if (updatecdr && chan->cdr)
1348                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1349                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1350                                                         if (option_verbose > 2)
1351                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1352                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1353                                                         /* Login this channel and wait for it to
1354                                                            go away */
1355                                                         p->chan = chan;
1356                                                         if (p->ackcall > 1)
1357                                                                 check_beep(p, 0);
1358                                                         else
1359                                                                 check_availability(p, 0);
1360                                                         ast_mutex_unlock(&p->lock);
1361                                                         ast_mutex_unlock(&agentlock);
1362                                                         while (res >= 0) {
1363                                                                 ast_mutex_lock(&p->lock);
1364                                                                 if (p->chan != chan)
1365                                                                         res = -1;
1366                                                                 ast_mutex_unlock(&p->lock);
1367                                                                 /* Yield here so other interested threads can kick in. */
1368                                                                 sched_yield();
1369                                                                 if (res)
1370                                                                         break;
1371
1372                                                                 ast_mutex_lock(&agentlock);
1373                                                                 ast_mutex_lock(&p->lock);
1374                                                                 if (p->lastdisc.tv_sec) {
1375                                                                         gettimeofday(&tv, NULL);
1376                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1377                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1378                                                                                         ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1379                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1380                                                                                 if (p->ackcall > 1)
1381                                                                                         check_beep(p, 0);
1382                                                                                 else
1383                                                                                         check_availability(p, 0);
1384                                                                         }
1385                                                                 }
1386                                                                 ast_mutex_unlock(&p->lock);
1387                                                                 ast_mutex_unlock(&agentlock);
1388                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1389                                                                 ast_mutex_lock( &p->app_lock );
1390                                                                 ast_mutex_lock(&p->lock);
1391                                                                 p->owning_app = pthread_self();
1392                                                                 ast_mutex_unlock(&p->lock);
1393                                                                 if (p->ackcall > 1) 
1394                                                                         res = agent_ack_sleep(p);
1395                                                                 else
1396                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1397                                                                                                         agent_cont_sleep, p );
1398                                                                 ast_mutex_unlock( &p->app_lock );
1399                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1400                                                                         ast_mutex_lock(&agentlock);
1401                                                                         ast_mutex_lock(&p->lock);
1402                                                                         check_availability(p, 0);
1403                                                                         ast_mutex_unlock(&p->lock);
1404                                                                         ast_mutex_unlock(&agentlock);
1405                                                                         res = 0;
1406                                                                 }
1407                                                                 sched_yield();
1408                                                         }
1409                                                         ast_mutex_lock(&p->lock);
1410                                                         if (res && p->owner) 
1411                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1412                                                         /* Log us off if appropriate */
1413                                                         if (p->chan == chan)
1414                                                                 p->chan = NULL;
1415                                                         p->acknowledged = 0;
1416                                                         logintime = time(NULL) - p->loginstart;
1417                                                         p->loginstart = 0;
1418                                                         ast_mutex_unlock(&p->lock);
1419                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1420                                                                 "Agent: %s\r\n"
1421                                                                 "Logintime: %ld\r\n"
1422                                                                 "Uniqueid: %s\r\n",
1423                                                                 p->agent, logintime, chan->uniqueid);
1424                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1425                                                         if (option_verbose > 2)
1426                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1427                                                         /* If there is no owner, go ahead and kill it now */
1428                                                         if (p->dead && !p->owner)
1429                                                                 free(p);
1430                                                 }
1431                                                 else {
1432                                                         ast_mutex_unlock(&p->lock);
1433                                                         p = NULL;
1434                                                 }
1435                                                 res = -1;
1436                                         } else {
1437                                                 ast_mutex_unlock(&p->lock);
1438                                                 errmsg = "agent-alreadyon";
1439                                                 p = NULL;
1440                                         }
1441                                         break;
1442                         }
1443                         ast_mutex_unlock(&p->lock);
1444                         p = p->next;
1445                 }
1446                 if (!p)
1447                         ast_mutex_unlock(&agentlock);
1448
1449                 if (!res)
1450                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1451         }
1452                 
1453         LOCAL_USER_REMOVE(u);
1454         /* Always hangup */
1455         return -1;
1456 }
1457
1458 static int login_exec(struct ast_channel *chan, void *data)
1459 {
1460         return __login_exec(chan, data, 0);
1461 }
1462
1463 static int callback_exec(struct ast_channel *chan, void *data)
1464 {
1465         return __login_exec(chan, data, 1);
1466 }
1467
1468 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1469 {
1470         int exitifnoagentid = 0;
1471         int nowarnings = 0;
1472         int res = 0;
1473         char agent[AST_MAX_AGENT], *tmp;
1474         if (data) {
1475                 if (strchr(data, 'd'))
1476                         exitifnoagentid = 1;
1477                 if (strchr(data, 'n'))
1478                         nowarnings = 1;
1479         }
1480         if (chan->callerid) {
1481                 char agentvar[AST_MAX_BUF];
1482                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->callerid);
1483                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1484                         struct agent_pvt *p = agents;
1485                         strncpy(agent, tmp, sizeof(agent) - 1);
1486                         ast_mutex_lock(&agentlock);
1487                         while (p) {
1488                                 if (!strcasecmp(p->agent, tmp)) {
1489                                         __agent_start_monitoring(chan, p, 1);
1490                                         break;
1491                                 }
1492                                 p = p->next;
1493                         }
1494                         ast_mutex_unlock(&agentlock);
1495                         
1496                 } else {
1497                         res = -1;
1498                         if (!nowarnings)
1499                                 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);
1500                 }
1501         } else {
1502                 res = -1;
1503                 if (!nowarnings)
1504                         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");
1505         }
1506         /* check if there is n + 101 priority */
1507         if (res) {
1508                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
1509                         chan->priority+=100;
1510                         ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1511                }
1512                 else if (exitifnoagentid)
1513                         return res;
1514         }
1515         return 0;
1516 }
1517
1518 int load_module()
1519 {
1520         /* Make sure we can register our sip channel type */
1521         if (ast_channel_register(type, tdesc, capability, agent_request)) {
1522                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1523                 return -1;
1524         }
1525         ast_register_application(app, login_exec, synopsis, descrip);
1526         ast_register_application(app2, callback_exec, synopsis2, descrip2);
1527         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1528         ast_cli_register(&cli_show_agents);
1529         /* Read in the config */
1530         read_agent_config();
1531         return 0;
1532 }
1533
1534 int reload()
1535 {
1536         read_agent_config();
1537         return 0;
1538 }
1539
1540 int unload_module()
1541 {
1542         struct agent_pvt *p;
1543         /* First, take us out of the channel loop */
1544         ast_cli_unregister(&cli_show_agents);
1545         ast_unregister_application(app);
1546         ast_unregister_application(app2);
1547         ast_unregister_application(app3);
1548         ast_channel_unregister(type);
1549         if (!ast_mutex_lock(&agentlock)) {
1550                 /* Hangup all interfaces if they have an owner */
1551                 p = agents;
1552                 while(p) {
1553                         if (p->owner)
1554                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1555                         p = p->next;
1556                 }
1557                 agents = NULL;
1558                 ast_mutex_unlock(&agentlock);
1559         } else {
1560                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1561                 return -1;
1562         }               
1563         return 0;
1564 }
1565
1566 int usecount()
1567 {
1568         int res;
1569         ast_mutex_lock(&usecnt_lock);
1570         res = usecnt;
1571         ast_mutex_unlock(&usecnt_lock);
1572         return res;
1573 }
1574
1575 char *key()
1576 {
1577         return ASTERISK_GPL_KEY;
1578 }
1579
1580 char *description()
1581 {
1582         return desc;
1583 }
1584