Uhm, that should be 0!
[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                         /* Store last disconnect time */
519                         if (p->wrapuptime) {
520                                 gettimeofday(&p->lastdisc, NULL);
521                                 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
522                                 if (p->lastdisc.tv_usec >= 1000000) {
523                                         p->lastdisc.tv_usec -= 1000000;
524                                         p->lastdisc.tv_sec++;
525                                 }
526                                 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
527                         } else
528                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
529                         if (p->chan) {
530                                 /* Recognize the hangup and pass it along immediately */
531                                 ast_hangup(p->chan);
532                                 p->chan = NULL;
533                         }
534                         ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
535                         if (howlong  && p->autologoff && (howlong > p->autologoff)) {
536                                 char agent[AST_MAX_AGENT] = "";
537                                 long logintime = time(NULL) - p->loginstart;
538                                 p->loginstart = 0;
539                                 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
540                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
541                                         "Agent: %s\r\n"
542                                         "Loginchan: %s\r\n"
543                                         "Logintime: %ld\r\n"
544                                         "Reason: Autologoff\r\n"
545                                         "Uniqueid: %s\r\n",
546                                         p->agent, p->loginchan, logintime, ast->uniqueid);
547                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
548                                 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
549                                 p->loginchan[0] = '\0';
550                         }
551                 } else if (p->dead) {
552                         ast_mutex_lock(&p->chan->lock);
553                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
554                         ast_mutex_unlock(&p->chan->lock);
555                 } else {
556                         ast_mutex_lock(&p->chan->lock);
557                         ast_moh_start(p->chan, p->moh);
558                         ast_mutex_unlock(&p->chan->lock);
559                 }
560         }
561 #if 0
562                 ast_mutex_unlock(&p->lock);
563                 /* Release ownership of the agent to other threads (presumably running the login app). */
564                 ast_mutex_unlock(&p->app_lock);
565         } else if (p->dead) {
566                 /* Go ahead and lose it */
567                 ast_mutex_unlock(&p->lock);
568                 /* Release ownership of the agent to other threads (presumably running the login app). */
569                 ast_mutex_unlock(&p->app_lock);
570         } else {
571                 ast_mutex_unlock(&p->lock);
572                 /* Release ownership of the agent to other threads (presumably running the login app). */
573                 ast_mutex_unlock(&p->app_lock);
574         }
575 #endif  
576         ast_mutex_unlock(&p->lock);
577
578         if (p->pending) {
579                 ast_mutex_lock(&agentlock);
580                 agent_unlink(p);
581                 ast_mutex_unlock(&agentlock);
582         }
583         if (p->abouttograb) {
584                 /* Let the "about to grab" thread know this isn't valid anymore, and let it
585                    kill it later */
586                 p->abouttograb = 0;
587         } else if (p->dead) {
588                 ast_mutex_destroy(&p->lock);
589                 ast_mutex_destroy(&p->app_lock);
590                 free(p);
591         } else {
592                 if (p->chan) {
593                         /* Not dead -- check availability now */
594                         ast_mutex_lock(&p->lock);
595                         /* Store last disconnect time */
596                         gettimeofday(&p->lastdisc, NULL);
597                         ast_mutex_unlock(&p->lock);
598                 }
599                 /* Release ownership of the agent to other threads (presumably running the login app). */
600                 ast_mutex_unlock(&p->app_lock);
601         }
602         return 0;
603 }
604
605 static int agent_cont_sleep( void *data )
606 {
607         struct agent_pvt *p;
608         struct timeval tv;
609         int res;
610
611         p = (struct agent_pvt *)data;
612
613         ast_mutex_lock(&p->lock);
614         res = p->app_sleep_cond;
615         if (p->lastdisc.tv_sec) {
616                 gettimeofday(&tv, NULL);
617                 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
618                         (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) 
619                         res = 1;
620         }
621         ast_mutex_unlock(&p->lock);
622 #if 0
623         if( !res )
624                 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
625 #endif          
626         return res;
627 }
628
629 static int agent_ack_sleep( void *data )
630 {
631         struct agent_pvt *p;
632         int res=0;
633         int to = 1000;
634         struct ast_frame *f;
635
636         /* Wait a second and look for something */
637
638         p = (struct agent_pvt *)data;
639         if (p->chan) {
640                 for(;;) {
641                         to = ast_waitfor(p->chan, to);
642                         if (to < 0) {
643                                 res = -1;
644                                 break;
645                         }
646                         if (!to) {
647                                 res = 0;
648                                 break;
649                         }
650                         f = ast_read(p->chan);
651                         if (!f) {
652                                 res = -1;
653                                 break;
654                         }
655                         if (f->frametype == AST_FRAME_DTMF)
656                                 res = f->subclass;
657                         else
658                                 res = 0;
659                         ast_frfree(f);
660                         ast_mutex_lock(&p->lock);
661                         if (!p->app_sleep_cond) {
662                                 ast_mutex_unlock(&p->lock);
663                                 res = 0;
664                                 break;
665                         } else if (res == '#') {
666                                 ast_mutex_unlock(&p->lock);
667                                 res = 1;
668                                 break;
669                         }
670                         ast_mutex_unlock(&p->lock);
671                         res = 0;
672                 }
673         } else
674                 res = -1;
675         return res;
676 }
677
678 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
679 {
680         struct ast_channel *tmp;
681         struct ast_frame null_frame = { AST_FRAME_NULL };
682 #if 0
683         if (!p->chan) {
684                 ast_log(LOG_WARNING, "No channel? :(\n");
685                 return NULL;
686         }
687 #endif  
688         tmp = ast_channel_alloc(0);
689         if (tmp) {
690                 if (p->chan) {
691                         tmp->nativeformats = p->chan->nativeformats;
692                         tmp->writeformat = p->chan->writeformat;
693                         tmp->pvt->rawwriteformat = p->chan->writeformat;
694                         tmp->readformat = p->chan->readformat;
695                         tmp->pvt->rawreadformat = p->chan->readformat;
696                         strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
697                         strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
698                         strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
699                 } else {
700                         tmp->nativeformats = AST_FORMAT_SLINEAR;
701                         tmp->writeformat = AST_FORMAT_SLINEAR;
702                         tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
703                         tmp->readformat = AST_FORMAT_SLINEAR;
704                         tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
705                 }
706                 if (p->pending)
707                         snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
708                 else
709                         snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
710                 tmp->type = type;
711                 ast_setstate(tmp, state);
712                 tmp->pvt->pvt = p;
713                 tmp->pvt->send_digit = agent_digit;
714                 tmp->pvt->call = agent_call;
715                 tmp->pvt->hangup = agent_hangup;
716                 tmp->pvt->answer = agent_answer;
717                 tmp->pvt->read = agent_read;
718                 tmp->pvt->write = agent_write;
719                 tmp->pvt->exception = agent_read;
720                 tmp->pvt->indicate = agent_indicate;
721                 tmp->pvt->fixup = agent_fixup;
722                 p->owner = tmp;
723                 ast_mutex_lock(&usecnt_lock);
724                 usecnt++;
725                 ast_mutex_unlock(&usecnt_lock);
726                 ast_update_use_count();
727                 tmp->priority = 1;
728                 /* Wake up and wait for other applications (by definition the login app)
729                  * to release this channel). Takes ownership of the agent channel
730                  * to this thread only.
731                  * For signalling the other thread, ast_queue_frame is used until we
732                  * can safely use signals for this purpose. The pselect() needs to be
733                  * implemented in the kernel for this.
734                  */
735                 p->app_sleep_cond = 0;
736                 if( ast_mutex_trylock(&p->app_lock) )
737                 {
738                         if (p->chan) {
739                                 ast_queue_frame(p->chan, &null_frame);
740                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
741                                 ast_mutex_lock(&p->app_lock);
742                                 ast_mutex_lock(&p->lock);
743                         }
744                         if( !p->chan )
745                         {
746                                 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
747                                 p->owner = NULL;
748                                 tmp->pvt->pvt = NULL;
749                                 p->app_sleep_cond = 1;
750                                 ast_channel_free( tmp );
751                                 ast_mutex_unlock(&p->lock);     /* For other thread to read the condition. */
752                                 ast_mutex_unlock(&p->app_lock);
753                                 return NULL;
754                         }
755                 }
756                 p->owning_app = pthread_self();
757                 /* After the above step, there should not be any blockers. */
758                 if (p->chan) {
759                         if (p->chan->blocking) {
760                                 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
761                                 CRASH;
762                         }
763                         ast_moh_stop(p->chan);
764                 }
765         } else
766                 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
767         return tmp;
768 }
769
770
771 static int read_agent_config(void)
772 {
773         struct ast_config *cfg;
774         struct ast_variable *v;
775         struct agent_pvt *p, *pl, *pn;
776         group = 0;
777         autologoff = 0;
778         wrapuptime = 0;
779         ackcall = 1;
780         cfg = ast_load(config);
781         if (!cfg) {
782                 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
783                 return 0;
784         }
785         ast_mutex_lock(&agentlock);
786         p = agents;
787         while(p) {
788                 p->dead = 1;
789                 p = p->next;
790         }
791         strncpy(moh, "default", sizeof(moh) - 1);
792         /* set the default recording values */
793         recordagentcalls = 0;
794         createlink = 0;
795         strncpy(recordformat, "wav", sizeof(recordformat) - 1);
796         strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
797         urlprefix[0] = '\0';
798         savecallsin[0] = '\0';
799
800         v = ast_variable_browse(cfg, "agents");
801         while(v) {
802                 /* Create the interface list */
803                 if (!strcasecmp(v->name, "agent")) {
804                         add_agent(v->value, 0);
805                 } else if (!strcasecmp(v->name, "group")) {
806                         group = ast_get_group(v->value);
807                 } else if (!strcasecmp(v->name, "autologoff")) {
808                         autologoff = atoi(v->value);
809                         if (autologoff < 0)
810                                 autologoff = 0;
811                 } else if (!strcasecmp(v->name, "ackcall")) {
812                         if (!strcasecmp(v->value, "always"))
813                                 ackcall = 2;
814                         else if (ast_true(v->value))
815                 ackcall = 1;
816                         else
817                                 ackcall = 0;
818                 } else if (!strcasecmp(v->name, "wrapuptime")) {
819                         wrapuptime = atoi(v->value);
820                         if (wrapuptime < 0)
821                                 wrapuptime = 0;
822                 } else if (!strcasecmp(v->name, "musiconhold")) {
823                         strncpy(moh, v->value, sizeof(moh) - 1);
824                 } else if (!strcasecmp(v->name, "updatecdr")) {
825                         updatecdr = ast_true(v->value);
826                 } else if (!strcasecmp(v->name, "recordagentcalls")) {
827                         recordagentcalls = ast_true(v->value);
828                 } else if (!strcasecmp(v->name, "createlink")) {
829                         createlink = ast_true(v->value);
830                 } else if (!strcasecmp(v->name, "recordformat")) {
831                         strncpy(recordformat, v->value, sizeof(recordformat) - 1);
832                         if (!strcasecmp(v->value, "wav49"))
833                                 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
834                         else
835                                 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
836                 } else if (!strcasecmp(v->name, "urlprefix")) {
837                         strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
838                         if (urlprefix[strlen(urlprefix) - 1] != '/')
839                                 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
840                 } else if (!strcasecmp(v->name, "savecallsin")) {
841                         if (v->value[0] == '/')
842                                 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
843                         else
844                                 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
845                         if (savecallsin[strlen(savecallsin) - 1] != '/')
846                                 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
847                 } else if (!strcasecmp(v->name, "custom_beep")) {
848                         strncpy(beep, v->value, sizeof(beep) - 1);
849                 }
850                 v = v->next;
851         }
852         p = agents;
853         pl = NULL;
854         while(p) {
855                 pn = p->next;
856                 if (p->dead) {
857                         /* Unlink */
858                         if (pl)
859                                 pl->next = p->next;
860                         else
861                                 agents = p->next;
862                         /* Destroy if  appropriate */
863                         if (!p->owner) {
864                                 if (!p->chan) {
865                                         ast_mutex_destroy(&p->lock);
866                                         ast_mutex_destroy(&p->app_lock);
867                                         free(p);
868                                 } else {
869                                         /* Cause them to hang up */
870                                         ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
871                                 }
872                         }
873                 } else
874                         pl = p;
875                 p = pn;
876         }
877         ast_mutex_unlock(&agentlock);
878         ast_destroy(cfg);
879         return 0;
880 }
881
882 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
883 {
884         struct ast_channel *chan=NULL, *parent=NULL;
885         struct agent_pvt *p;
886         int res;
887         ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
888         if (needlock)
889                 ast_mutex_lock(&agentlock);
890         p = agents;
891         while(p) {
892                 if (p == newlyavailable) {
893                         p = p->next;
894                         continue;
895                 }
896                 ast_mutex_lock(&p->lock);
897                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
898                         ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
899                         /* We found a pending call, time to merge */
900                         chan = agent_new(newlyavailable, AST_STATE_DOWN);
901                         parent = p->owner;
902                         p->abouttograb = 1;
903                         ast_mutex_unlock(&p->lock);
904                         break;
905                 }
906                 ast_mutex_unlock(&p->lock);
907                 p = p->next;
908         }
909         if (needlock)
910                 ast_mutex_unlock(&agentlock);
911         if (parent && chan)  {
912                 if (newlyavailable->ackcall > 1) {
913                         /* Don't do beep here */
914                         res = 0;
915                 } else {
916                         ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
917                         res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
918                         ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
919                         if (!res) {
920                                 res = ast_waitstream(newlyavailable->chan, "");
921                                 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
922                         }
923                 }
924                 if (!res) {
925                         /* Note -- parent may have disappeared */
926                         if (p->abouttograb) {
927                                 newlyavailable->acknowledged = 1;
928                                 ast_setstate(parent, AST_STATE_UP);
929                                 ast_setstate(chan, AST_STATE_UP);
930                                 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
931                                 /* Go ahead and mark the channel as a zombie so that masquerade will
932                                    destroy it for us, and we need not call ast_hangup */
933                                 ast_mutex_lock(&parent->lock);
934                                 chan->zombie = 1;
935                                 ast_channel_masquerade(parent, chan);
936                                 ast_mutex_unlock(&parent->lock);
937                                 p->abouttograb = 0;
938                         } else {
939                                 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
940                                 agent_cleanup(newlyavailable);
941                         }
942                 } else {
943                         ast_log(LOG_DEBUG, "Ugh...  Agent hung up at exactly the wrong time\n");
944                         agent_cleanup(newlyavailable);
945                 }
946         }
947         return 0;
948 }
949
950 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
951 {
952         struct agent_pvt *p;
953         int res=0;
954         ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
955         if (needlock)
956                 ast_mutex_lock(&agentlock);
957         p = agents;
958         while(p) {
959                 if (p == newlyavailable) {
960                         p = p->next;
961                         continue;
962                 }
963                 ast_mutex_lock(&p->lock);
964                 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
965                         ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
966                         ast_mutex_unlock(&p->lock);
967                         break;
968                 }
969                 ast_mutex_unlock(&p->lock);
970                 p = p->next;
971         }
972         if (needlock)
973                 ast_mutex_unlock(&agentlock);
974         if (p) {
975                 ast_mutex_unlock(&newlyavailable->lock);
976                 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
977                 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
978                 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
979                 if (!res) {
980                         res = ast_waitstream(newlyavailable->chan, "");
981                         ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
982                 }
983                 ast_mutex_lock(&newlyavailable->lock);
984         }
985         return res;
986 }
987
988 static struct ast_channel *agent_request(char *type, int format, void *data)
989 {
990         struct agent_pvt *p;
991         struct ast_channel *chan = NULL;
992         char *s;
993         unsigned int groupmatch;
994         int waitforagent=0;
995         int hasagent = 0;
996         s = data;
997         if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
998                 groupmatch = (1 << groupmatch);
999         } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1000                 groupmatch = (1 << groupmatch);
1001                 waitforagent = 1;
1002         } else {
1003                 groupmatch = 0;
1004         }
1005
1006         /* Check actual logged in agents first */
1007         ast_mutex_lock(&agentlock);
1008         p = agents;
1009         while(p) {
1010                 ast_mutex_lock(&p->lock);
1011                 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1012                                 ast_strlen_zero(p->loginchan)) {
1013                         if (p->chan)
1014                                 hasagent++;
1015                         if (!p->lastdisc.tv_sec) {
1016                                 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1017                                 if (!p->owner && p->chan) {
1018                                         /* Fixed agent */
1019                                         chan = agent_new(p, AST_STATE_DOWN);
1020                                 }
1021                                 if (chan) {
1022                                         ast_mutex_unlock(&p->lock);
1023                                         break;
1024                                 }
1025                         }
1026                 }
1027                 ast_mutex_unlock(&p->lock);
1028                 p = p->next;
1029         }
1030         if (!p) {
1031                 p = agents;
1032                 while(p) {
1033                         ast_mutex_lock(&p->lock);
1034                         if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1035                                 if (p->chan || !ast_strlen_zero(p->loginchan))
1036                                         hasagent++;
1037                                 if (!p->lastdisc.tv_sec || (time(NULL) > p->lastdisc.tv_sec)) {
1038                                         memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1039                                         /* Agent must be registered, but not have any active call, and not be in a waiting state */
1040                                         if (!p->owner && p->chan) {
1041                                                 /* Could still get a fixed agent */
1042                                                 chan = agent_new(p, AST_STATE_DOWN);
1043                                         } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1044                                                 /* Adjustable agent */
1045                                                 p->chan = ast_request("Local", format, p->loginchan);
1046                                                 if (p->chan)
1047                                                         chan = agent_new(p, AST_STATE_DOWN);
1048                                         }
1049                                         if (chan) {
1050                                                 ast_mutex_unlock(&p->lock);
1051                                                 break;
1052                                         }
1053                                 }
1054                         }
1055                         ast_mutex_unlock(&p->lock);
1056                         p = p->next;
1057                 }
1058         }
1059
1060         if (!chan && waitforagent) {
1061                 /* No agent available -- but we're requesting to wait for one.
1062                    Allocate a place holder */
1063                 if (hasagent) {
1064                         ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1065                         p = add_agent(data, 1);
1066                         p->group = groupmatch;
1067                         chan = agent_new(p, AST_STATE_DOWN);
1068                         if (!chan) {
1069                                 ast_log(LOG_WARNING, "Weird...  Fix this to drop the unused pending agent\n");
1070                         }
1071                 } else
1072                         ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1073         }
1074         ast_mutex_unlock(&agentlock);
1075         return chan;
1076 }
1077
1078 static int powerof(unsigned int v)
1079 {
1080         int x;
1081         for (x=0;x<32;x++) {
1082                 if (v & (1 << x)) return x;
1083         }
1084         return 0;
1085 }
1086
1087 static int agents_show(int fd, int argc, char **argv)
1088 {
1089         struct agent_pvt *p;
1090         char username[AST_MAX_BUF];
1091         char location[AST_MAX_BUF] = "";
1092         char talkingto[AST_MAX_BUF] = "";
1093         char moh[AST_MAX_BUF];
1094
1095         if (argc != 2)
1096                 return RESULT_SHOWUSAGE;
1097         ast_mutex_lock(&agentlock);
1098         p = agents;
1099         while(p) {
1100                 ast_mutex_lock(&p->lock);
1101                 if (p->pending) {
1102                         if (p->group)
1103                                 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1104                         else
1105                                 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1106                 } else {
1107                         if (!ast_strlen_zero(p->name))
1108                                 snprintf(username, sizeof(username), "(%s) ", p->name);
1109                         else
1110                                 username[0] = '\0';
1111                         if (p->chan) {
1112                                 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1113                                 if (p->owner && p->owner->bridge) {
1114                                         snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
1115                                 } else {
1116                                         strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1117                                 }
1118                         } else if (!ast_strlen_zero(p->loginchan)) {
1119                                 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1120                                 talkingto[0] = '\0';
1121                                 if (p->acknowledged)
1122                                         strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1123                         } else {
1124                                 strncpy(location, "not logged in", sizeof(location) - 1);
1125                                 talkingto[0] = '\0';
1126                         }
1127                         if (!ast_strlen_zero(p->moh))
1128                                 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1129                         ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent, 
1130                                         username, location, talkingto, moh);
1131                 }
1132                 ast_mutex_unlock(&p->lock);
1133                 p = p->next;
1134         }
1135         ast_mutex_unlock(&agentlock);
1136         return RESULT_SUCCESS;
1137 }
1138
1139 static char show_agents_usage[] = 
1140 "Usage: show agents\n"
1141 "       Provides summary information on agents.\n";
1142
1143 static struct ast_cli_entry cli_show_agents = {
1144         { "show", "agents", NULL }, agents_show, 
1145         "Show status of agents", show_agents_usage, NULL };
1146
1147 STANDARD_LOCAL_USER;
1148 LOCAL_USER_DECL;
1149
1150 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1151 {
1152         int res=0;
1153         int tries = 0;
1154         struct agent_pvt *p;
1155         struct localuser *u;
1156         struct timeval tv;
1157         char user[AST_MAX_AGENT] = "";
1158         char pass[AST_MAX_AGENT];
1159         char agent[AST_MAX_AGENT] = "";
1160         char xpass[AST_MAX_AGENT] = "";
1161         char *errmsg;
1162         char info[512];
1163         char *opt_user = NULL;
1164         char *options = NULL;
1165         char *context = NULL;
1166         char *exten = NULL;
1167         int play_announcement;
1168         char *filename = "agent-loginok";
1169         
1170         LOCAL_USER_ADD(u);
1171
1172         /* Parse the arguments XXX Check for failure XXX */
1173         strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1174         opt_user = info;
1175         if( opt_user ) {
1176                 options = strchr(opt_user, '|');
1177                 if (options) {
1178                         *options = '\0';
1179                         options++;
1180                         if (callbackmode) {
1181                                 context = strchr(options, '@');
1182                                 if (context) {
1183                                         *context = '\0';
1184                                         context++;
1185                                 }
1186                                 exten = options;
1187                                 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1188                                 if (!*exten)
1189                                         exten = NULL;
1190                         }
1191                 }
1192         }
1193
1194         if (chan->_state != AST_STATE_UP)
1195                 res = ast_answer(chan);
1196         if (!res) {
1197                 if( opt_user && !ast_strlen_zero(opt_user))
1198                         strncpy( user, opt_user, AST_MAX_AGENT - 1);
1199                 else
1200                         res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1201         }
1202         while (!res && (tries < 3)) {
1203                 /* Check for password */
1204                 ast_mutex_lock(&agentlock);
1205                 p = agents;
1206                 while(p) {
1207                         if (!strcmp(p->agent, user) && !p->pending)
1208                                 strncpy(xpass, p->password, sizeof(xpass) - 1);
1209                         p = p->next;
1210                 }
1211                 ast_mutex_unlock(&agentlock);
1212                 if (!res) {
1213                         if (!ast_strlen_zero(xpass))
1214                                 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1215                         else
1216                                 pass[0] = '\0';
1217                 }
1218                 errmsg = "agent-incorrect";
1219
1220 #if 0
1221                 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1222 #endif          
1223
1224                 /* Check again for accuracy */
1225                 ast_mutex_lock(&agentlock);
1226                 p = agents;
1227                 while(p) {
1228                         ast_mutex_lock(&p->lock);
1229                         if (!strcmp(p->agent, user) &&
1230                                 !strcmp(p->password, pass) && !p->pending) {
1231                                         if (!p->chan) {
1232                                                 char last_loginchan[80] = "";
1233                                                 long logintime;
1234                                                 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1235
1236                                                 if (callbackmode) {
1237                                                         char tmpchan[AST_MAX_BUF] = "";
1238                                                         int pos = 0;
1239                                                         /* Retrieve login chan */
1240                                                         for (;;) {
1241                                                                 if (exten) {
1242                                                                         strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1243                                                                         res = 0;
1244                                                                 } else
1245                                                                         res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1246                                                                 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1247                                                                                         1, NULL))
1248                                                                         break;
1249                                                                 if (exten) {
1250                                                                         ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1251                                                                         exten = NULL;
1252                                                                         pos = 0;
1253                                                                 } else {
1254                                                                         res = ast_streamfile(chan, "invalid", chan->language);
1255                                                                         if (!res)
1256                                                                                 res = ast_waitstream(chan, AST_DIGIT_ANY);
1257                                                                         if (res > 0) {
1258                                                                                 tmpchan[0] = res;
1259                                                                                 tmpchan[1] = '\0';
1260                                                                                 pos = 1;
1261                                                                         } else {
1262                                                                                 tmpchan[0] = '\0';
1263                                                                                 pos = 0;
1264                                                                         }
1265                                                                 }
1266                                                         }
1267                                                         if (!res) {
1268                                                                 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1269                                                                         snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1270                                                                 else {
1271                                                                         strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1272                                                                         strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1273                                                                 }
1274                                                                 if (ast_strlen_zero(p->loginchan))
1275                                                                         filename = "agent-loggedoff";
1276                                                                 p->acknowledged = 0;
1277                                                                 /* store/clear the global variable that stores agentid based on the callerid */
1278                                                                 if (chan->callerid) {
1279                                                                         char agentvar[AST_MAX_BUF];
1280                                                                         snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->callerid);
1281                                                                         if (ast_strlen_zero(p->loginchan))
1282                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1283                                                                         else
1284                                                                                 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1285                                                                 }
1286                                                                 if(updatecdr && chan->cdr)
1287                                                                         snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1288
1289                                                         }
1290                                                 } else {
1291                                                         p->loginchan[0] = '\0';
1292                                                         p->acknowledged = 0;
1293                                                 }
1294                                                 play_announcement = 1;
1295                                                 if( options )
1296                                                         if( strchr( options, 's' ) )
1297                                                                 play_announcement = 0;
1298                                                 ast_mutex_unlock(&p->lock);
1299                                                 ast_mutex_unlock(&agentlock);
1300                                                 if( !res && play_announcement )
1301                                                         res = ast_streamfile(chan, filename, chan->language);
1302                                                 if (!res)
1303                                                         ast_waitstream(chan, "");
1304                                                 ast_mutex_lock(&agentlock);
1305                                                 ast_mutex_lock(&p->lock);
1306                                                 if (!res) {
1307                                                         res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1308                                                         if (res)
1309                                                                 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1310                                                 }
1311                                                 if (!res) {
1312                                                         ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1313                                                         if (res)
1314                                                                 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1315                                                 }
1316                                                 /* Check once more just in case */
1317                                                 if (p->chan)
1318                                                         res = -1;
1319                                                 if (callbackmode && !res) {
1320                                                         /* Just say goodbye and be done with it */
1321                                                         if (!ast_strlen_zero(p->loginchan)) {
1322                                                                 if (p->loginstart == 0)
1323                                                                         time(&p->loginstart);
1324                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1325                                                                         "Agent: %s\r\n"
1326                                                                         "Loginchan: %s\r\n"
1327                                                                         "Uniqueid: %s\r\n",
1328                                                                         p->agent, p->loginchan, chan->uniqueid);
1329                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1330                                                                 if (option_verbose > 2)
1331                                                                         ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1332                                                         } else {
1333                                                                 logintime = time(NULL) - p->loginstart;
1334                                                                 p->loginstart = 0;
1335                                                                 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1336                                                                         "Agent: %s\r\n"
1337                                                                         "Loginchan: %s\r\n"
1338                                                                         "Logintime: %ld\r\n"
1339                                                                         "Uniqueid: %s\r\n",
1340                                                                         p->agent, last_loginchan, logintime, chan->uniqueid);
1341                                                                 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1342                                                                 if (option_verbose > 2)
1343                                                                         ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged out\n", p->agent);
1344                                                         }
1345                                                         ast_mutex_unlock(&agentlock);
1346                                                         if (!res)
1347                                                                 res = ast_safe_sleep(chan, 500);
1348                                                         res = ast_streamfile(chan, "vm-goodbye", chan->language);
1349                                                         if (!res)
1350                                                                 res = ast_waitstream(chan, "");
1351                                                         if (!res)
1352                                                                 res = ast_safe_sleep(chan, 1000);
1353                                                         ast_mutex_unlock(&p->lock);
1354                                                 } else if (!res) {
1355 #ifdef HONOR_MUSIC_CLASS
1356                                                         /* check if the moh class was changed with setmusiconhold */
1357                                                         if (*(chan->musicclass))
1358                                                                 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1359 #endif                                                          
1360                                                         ast_moh_start(chan, p->moh);
1361                                                         if (p->loginstart == 0)
1362                                                                 time(&p->loginstart);
1363                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1364                                                                 "Agent: %s\r\n"
1365                                                                 "Channel: %s\r\n"
1366                                                                 "Uniqueid: %s\r\n",
1367                                                                 p->agent, chan->name, chan->uniqueid);
1368                                                         if (updatecdr && chan->cdr)
1369                                                                 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1370                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1371                                                         if (option_verbose > 2)
1372                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1373                                                                                                 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1374                                                         /* Login this channel and wait for it to
1375                                                            go away */
1376                                                         p->chan = chan;
1377                                                         if (p->ackcall > 1)
1378                                                                 check_beep(p, 0);
1379                                                         else
1380                                                                 check_availability(p, 0);
1381                                                         ast_mutex_unlock(&p->lock);
1382                                                         ast_mutex_unlock(&agentlock);
1383                                                         while (res >= 0) {
1384                                                                 ast_mutex_lock(&p->lock);
1385                                                                 if (p->chan != chan)
1386                                                                         res = -1;
1387                                                                 ast_mutex_unlock(&p->lock);
1388                                                                 /* Yield here so other interested threads can kick in. */
1389                                                                 sched_yield();
1390                                                                 if (res)
1391                                                                         break;
1392
1393                                                                 ast_mutex_lock(&agentlock);
1394                                                                 ast_mutex_lock(&p->lock);
1395                                                                 if (p->lastdisc.tv_sec) {
1396                                                                         gettimeofday(&tv, NULL);
1397                                                                         if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 + 
1398                                                                                 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1399                                                                                         ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1400                                                                                 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1401                                                                                 if (p->ackcall > 1)
1402                                                                                         check_beep(p, 0);
1403                                                                                 else
1404                                                                                         check_availability(p, 0);
1405                                                                         }
1406                                                                 }
1407                                                                 ast_mutex_unlock(&p->lock);
1408                                                                 ast_mutex_unlock(&agentlock);
1409                                                                 /*      Synchronize channel ownership between call to agent and itself. */
1410                                                                 ast_mutex_lock( &p->app_lock );
1411                                                                 ast_mutex_lock(&p->lock);
1412                                                                 p->owning_app = pthread_self();
1413                                                                 ast_mutex_unlock(&p->lock);
1414                                                                 if (p->ackcall > 1) 
1415                                                                         res = agent_ack_sleep(p);
1416                                                                 else
1417                                                                         res = ast_safe_sleep_conditional( chan, 1000,
1418                                                                                                         agent_cont_sleep, p );
1419                                                                 ast_mutex_unlock( &p->app_lock );
1420                                                                 if ((p->ackcall > 1)  && (res == 1)) {
1421                                                                         ast_mutex_lock(&agentlock);
1422                                                                         ast_mutex_lock(&p->lock);
1423                                                                         check_availability(p, 0);
1424                                                                         ast_mutex_unlock(&p->lock);
1425                                                                         ast_mutex_unlock(&agentlock);
1426                                                                         res = 0;
1427                                                                 }
1428                                                                 sched_yield();
1429                                                         }
1430                                                         ast_mutex_lock(&p->lock);
1431                                                         if (res && p->owner) 
1432                                                                 ast_log(LOG_WARNING, "Huh?  We broke out when there was still an owner?\n");
1433                                                         /* Log us off if appropriate */
1434                                                         if (p->chan == chan)
1435                                                                 p->chan = NULL;
1436                                                         p->acknowledged = 0;
1437                                                         logintime = time(NULL) - p->loginstart;
1438                                                         p->loginstart = 0;
1439                                                         ast_mutex_unlock(&p->lock);
1440                                                         manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1441                                                                 "Agent: %s\r\n"
1442                                                                 "Logintime: %ld\r\n"
1443                                                                 "Uniqueid: %s\r\n",
1444                                                                 p->agent, logintime, chan->uniqueid);
1445                                                         ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1446                                                         if (option_verbose > 2)
1447                                                                 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1448                                                         /* If there is no owner, go ahead and kill it now */
1449                                                         if (p->dead && !p->owner) {
1450                                                                 ast_mutex_destroy(&p->lock);
1451                                                                 ast_mutex_destroy(&p->app_lock);
1452                                                                 free(p);
1453                                                         }
1454                                                 }
1455                                                 else {
1456                                                         ast_mutex_unlock(&p->lock);
1457                                                         p = NULL;
1458                                                 }
1459                                                 res = -1;
1460                                         } else {
1461                                                 ast_mutex_unlock(&p->lock);
1462                                                 errmsg = "agent-alreadyon";
1463                                                 p = NULL;
1464                                         }
1465                                         break;
1466                         }
1467                         ast_mutex_unlock(&p->lock);
1468                         p = p->next;
1469                 }
1470                 if (!p)
1471                         ast_mutex_unlock(&agentlock);
1472
1473                 if (!res)
1474                         res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1475         }
1476                 
1477         LOCAL_USER_REMOVE(u);
1478         /* Always hangup */
1479         return -1;
1480 }
1481
1482 static int login_exec(struct ast_channel *chan, void *data)
1483 {
1484         return __login_exec(chan, data, 0);
1485 }
1486
1487 static int callback_exec(struct ast_channel *chan, void *data)
1488 {
1489         return __login_exec(chan, data, 1);
1490 }
1491
1492 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1493 {
1494         int exitifnoagentid = 0;
1495         int nowarnings = 0;
1496         int res = 0;
1497         char agent[AST_MAX_AGENT], *tmp;
1498         if (data) {
1499                 if (strchr(data, 'd'))
1500                         exitifnoagentid = 1;
1501                 if (strchr(data, 'n'))
1502                         nowarnings = 1;
1503         }
1504         if (chan->callerid) {
1505                 char agentvar[AST_MAX_BUF];
1506                 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->callerid);
1507                 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1508                         struct agent_pvt *p = agents;
1509                         strncpy(agent, tmp, sizeof(agent) - 1);
1510                         ast_mutex_lock(&agentlock);
1511                         while (p) {
1512                                 if (!strcasecmp(p->agent, tmp)) {
1513                                         __agent_start_monitoring(chan, p, 1);
1514                                         break;
1515                                 }
1516                                 p = p->next;
1517                         }
1518                         ast_mutex_unlock(&agentlock);
1519                         
1520                 } else {
1521                         res = -1;
1522                         if (!nowarnings)
1523                                 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);
1524                 }
1525         } else {
1526                 res = -1;
1527                 if (!nowarnings)
1528                         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");
1529         }
1530         /* check if there is n + 101 priority */
1531         if (res) {
1532                if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
1533                         chan->priority+=100;
1534                         ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1535                }
1536                 else if (exitifnoagentid)
1537                         return res;
1538         }
1539         return 0;
1540 }
1541
1542 int load_module()
1543 {
1544         /* Make sure we can register our sip channel type */
1545         if (ast_channel_register(type, tdesc, capability, agent_request)) {
1546                 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1547                 return -1;
1548         }
1549         ast_register_application(app, login_exec, synopsis, descrip);
1550         ast_register_application(app2, callback_exec, synopsis2, descrip2);
1551         ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1552         ast_cli_register(&cli_show_agents);
1553         /* Read in the config */
1554         read_agent_config();
1555         return 0;
1556 }
1557
1558 int reload()
1559 {
1560         read_agent_config();
1561         return 0;
1562 }
1563
1564 int unload_module()
1565 {
1566         struct agent_pvt *p;
1567         /* First, take us out of the channel loop */
1568         ast_cli_unregister(&cli_show_agents);
1569         ast_unregister_application(app);
1570         ast_unregister_application(app2);
1571         ast_unregister_application(app3);
1572         ast_channel_unregister(type);
1573         if (!ast_mutex_lock(&agentlock)) {
1574                 /* Hangup all interfaces if they have an owner */
1575                 p = agents;
1576                 while(p) {
1577                         if (p->owner)
1578                                 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1579                         p = p->next;
1580                 }
1581                 agents = NULL;
1582                 ast_mutex_unlock(&agentlock);
1583         } else {
1584                 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1585                 return -1;
1586         }               
1587         return 0;
1588 }
1589
1590 int usecount()
1591 {
1592         int res;
1593         ast_mutex_lock(&usecnt_lock);
1594         res = usecnt;
1595         ast_mutex_unlock(&usecnt_lock);
1596         return res;
1597 }
1598
1599 char *key()
1600 {
1601         return ASTERISK_GPL_KEY;
1602 }
1603
1604 char *description()
1605 {
1606         return desc;
1607 }
1608