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