2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Session Initiation Protocol
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
17 #include <asterisk/lock.h>
18 #include <asterisk/channel.h>
19 #include <asterisk/channel_pvt.h>
20 #include <asterisk/config.h>
21 #include <asterisk/logger.h>
22 #include <asterisk/module.h>
23 #include <asterisk/pbx.h>
24 #include <asterisk/options.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/sched.h>
27 #include <asterisk/io.h>
28 #include <asterisk/rtp.h>
29 #include <asterisk/acl.h>
30 #include <asterisk/callerid.h>
31 #include <asterisk/file.h>
32 #include <asterisk/cli.h>
33 #include <asterisk/app.h>
34 #include <asterisk/musiconhold.h>
35 #include <asterisk/manager.h>
36 #include <asterisk/parking.h>
37 #include <sys/socket.h>
43 #include <arpa/inet.h>
44 #include <sys/signal.h>
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";
51 static char *app = "AgentLogin";
52 static char *app2 = "AgentCallbackLogin";
53 static char *app3 = "AgentMonitorOutgoing";
55 static char *synopsis = "Call agent login";
56 static char *synopsis2 = "Call agent callback login";
57 static char *synopsis3 = "Record agent's outgoing call";
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"
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";
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"
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 " 'c' - change the source channel in the CDR record for this call to agent/agent_id so that we know which agent generates the call\n"
79 " 'n' - don't generate the warnings when there is no callerid or the agentid is not known. It's handy if you want to have one context for agent and non-agent calls.\n";
81 static char moh[80] = "default";
83 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
84 #define AST_MAX_BUF 256
86 static int capability = -1;
88 static unsigned int group;
89 static int autologoff;
90 static int wrapuptime;
94 static ast_mutex_t usecnt_lock = AST_MUTEX_INITIALIZER;
96 /* Protect the interface list (of sip_pvt's) */
97 static ast_mutex_t agentlock = AST_MUTEX_INITIALIZER;
99 int recordagentcalls = 0;
100 char recordformat[AST_MAX_BUF];
101 char recordformatext[AST_MAX_BUF];
103 char urlprefix[AST_MAX_BUF];
104 char savecallsin[AST_MAX_BUF];
106 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
108 static struct agent_pvt {
109 ast_mutex_t lock; /* Channel private lock */
110 int dead; /* Poised for destruction? */
111 int pending; /* Not a real agent -- just pending a match */
112 int abouttograb; /* About to grab */
113 int autologoff; /* Auto timeout time */
114 int ackcall; /* ackcall */
115 time_t start; /* When call started */
116 struct timeval lastdisc; /* When last disconnected */
117 int wrapuptime; /* Wrapup time in ms */
118 unsigned int group; /* Group memberships */
119 int acknowledged; /* Acknowledged */
120 char moh[80]; /* Which music on hold */
121 char agent[AST_MAX_AGENT]; /* Agent ID */
122 char password[AST_MAX_AGENT]; /* Password for Agent login */
123 char name[AST_MAX_AGENT];
124 ast_mutex_t app_lock; /* Synchronization between owning applications */
125 volatile pthread_t owning_app; /* Owning application thread id */
126 volatile int app_sleep_cond; /* Sleep condition for the login app */
127 struct ast_channel *owner; /* Agent */
129 struct ast_channel *chan; /* Channel we use */
130 struct agent_pvt *next; /* Agent */
133 #define CHECK_FORMATS(ast, p) do { \
135 if (ast->nativeformats != p->chan->nativeformats) { \
136 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
137 /* Native formats changed, reset things */ \
138 ast->nativeformats = p->chan->nativeformats; \
139 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
140 ast_set_read_format(ast, ast->readformat); \
141 ast_set_write_format(ast, ast->writeformat); \
143 if (p->chan->readformat != ast->pvt->rawreadformat) \
144 ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
145 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
146 ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
150 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
151 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
152 totally impractical combinations XXX */
154 #define CLEANUP(ast, p) do { \
157 for (x=0;x<AST_MAX_FDS;x++) {\
158 if (x != AST_MAX_FDS - 2) \
159 ast->fds[x] = p->chan->fds[x]; \
161 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
166 static void agent_unlink(struct agent_pvt *agent)
168 struct agent_pvt *p, *prev;
174 prev->next = agent->next;
176 agents = agent->next;
184 static struct agent_pvt *add_agent(char *agent, int pending)
186 char tmp[AST_MAX_BUF];
187 char *password=NULL, *name=NULL;
188 struct agent_pvt *p, *prev;
190 strncpy(tmp, agent, sizeof(tmp));
191 if ((password = strchr(tmp, ','))) {
194 while (*password < 33) password++;
196 if (password && (name = strchr(password, ','))) {
199 while (*name < 33) name++;
204 if (!pending && !strcmp(p->agent, tmp))
210 p = malloc(sizeof(struct agent_pvt));
212 memset(p, 0, sizeof(struct agent_pvt));
213 strncpy(p->agent, tmp, sizeof(p->agent) -1);
214 ast_mutex_init( &p->lock );
215 ast_mutex_init( &p->app_lock );
216 p->owning_app = (pthread_t) -1;
217 p->app_sleep_cond = 1;
219 p->pending = pending;
230 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
231 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
232 strncpy(p->moh, moh, sizeof(p->moh) - 1);
233 p->ackcall = ackcall;
234 p->autologoff = autologoff;
235 p->wrapuptime = wrapuptime;
243 static int agent_cleanup(struct agent_pvt *p)
245 struct ast_channel *chan = p->owner;
247 chan->pvt->pvt = NULL;
248 p->app_sleep_cond = 1;
249 /* Release ownership of the agent to other threads (presumably running the login app). */
250 ast_mutex_unlock(&p->app_lock);
252 ast_channel_free(chan);
258 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
260 static int agent_answer(struct ast_channel *ast)
262 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
266 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
268 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
269 char filename[AST_MAX_BUF];
274 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
275 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
276 if ((pointer = strchr(tmp, '.')))
278 ast_monitor_start(ast, recordformat, tmp, needlock);
279 ast_monitor_setjoinfiles(ast, 1);
280 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
282 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
285 ast->cdr = ast_cdr_alloc();
286 ast_cdr_setuserfield(ast, tmp2);
289 ast_log(LOG_ERROR, "Recording already started on that call.\n");
293 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
295 return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
298 static struct ast_frame *agent_read(struct ast_channel *ast)
300 struct agent_pvt *p = ast->pvt->pvt;
301 struct ast_frame *f = NULL;
302 static struct ast_frame null_frame = { AST_FRAME_NULL, };
303 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
304 ast_mutex_lock(&p->lock);
305 CHECK_FORMATS(ast, p);
307 p->chan->exception = ast->exception;
308 if (ast->fdno == AST_MAX_FDS - 3)
309 p->chan->fdno = AST_MAX_FDS - 2;
311 p->chan->fdno = ast->fdno;
312 f = ast_read(p->chan);
316 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
318 /* Note that we don't hangup if it's not a callback because Asterisk will do it
319 for us when the PBX instance that called login finishes */
320 if (strlen(p->loginchan))
326 if (f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
329 if (option_verbose > 2)
330 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
331 /* Don't pass answer along */
340 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
341 if (!p->acknowledged) {
342 if (option_verbose > 2)
343 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
349 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
350 /* * terminates call */
355 ast_mutex_unlock(&p->lock);
356 if (f == &answer_frame)
357 agent_start_monitoring(ast,0);
361 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
363 struct agent_pvt *p = ast->pvt->pvt;
365 CHECK_FORMATS(ast, p);
366 ast_mutex_lock(&p->lock);
368 if ((f->frametype != AST_FRAME_VOICE) ||
369 (f->subclass == p->chan->writeformat)) {
370 res = ast_write(p->chan, f);
372 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
378 ast_mutex_unlock(&p->lock);
382 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
384 struct agent_pvt *p = newchan->pvt->pvt;
385 ast_mutex_lock(&p->lock);
386 if (p->owner != oldchan) {
387 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
388 ast_mutex_unlock(&p->lock);
392 ast_mutex_unlock(&p->lock);
396 static int agent_indicate(struct ast_channel *ast, int condition)
398 struct agent_pvt *p = ast->pvt->pvt;
400 ast_mutex_lock(&p->lock);
402 res = ast_indicate(p->chan, condition);
405 ast_mutex_unlock(&p->lock);
409 static int agent_digit(struct ast_channel *ast, char digit)
411 struct agent_pvt *p = ast->pvt->pvt;
413 ast_mutex_lock(&p->lock);
415 res = p->chan->pvt->send_digit(p->chan, digit);
418 ast_mutex_unlock(&p->lock);
422 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
424 struct agent_pvt *p = ast->pvt->pvt;
426 ast_mutex_lock(&p->lock);
430 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
431 ast_setstate(ast, AST_STATE_DIALING);
434 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
437 ast_mutex_unlock(&p->lock);
439 } else if (strlen(p->loginchan)) {
441 /* Call on this agent */
442 if (option_verbose > 2)
443 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
444 if (p->chan->callerid)
445 free(p->chan->callerid);
447 p->chan->callerid = strdup(ast->callerid);
449 p->chan->callerid = NULL;
450 res = ast_call(p->chan, p->loginchan, 0);
452 ast_mutex_unlock(&p->lock);
455 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
456 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
457 res = ast_streamfile(p->chan, "beep", p->chan->language);
458 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
460 res = ast_waitstream(p->chan, "");
461 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
464 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
465 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
467 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
474 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
475 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
477 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
481 /* Call is immediately up, or might need ack */
483 ast_setstate(ast, AST_STATE_RINGING);
485 ast_setstate(ast, AST_STATE_UP);
486 agent_start_monitoring(ast,0);
492 ast_mutex_unlock(&p->lock);
496 static int agent_hangup(struct ast_channel *ast)
498 struct agent_pvt *p = ast->pvt->pvt;
500 ast_mutex_lock(&p->lock);
502 ast->pvt->pvt = NULL;
503 p->app_sleep_cond = 1;
505 if (p->start && (ast->_state != AST_STATE_UP))
506 howlong = time(NULL) - p->start;
509 /* If they're dead, go ahead and hang up on the agent now */
510 if (strlen(p->loginchan)) {
512 /* Recognize the hangup and pass it along immediately */
516 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
517 if (howlong && p->autologoff && (howlong > p->autologoff)) {
518 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
519 strcpy(p->loginchan, "");
521 } else if (p->dead) {
522 ast_mutex_lock(&p->chan->lock);
523 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
524 ast_mutex_unlock(&p->chan->lock);
526 ast_mutex_lock(&p->chan->lock);
527 ast_moh_start(p->chan, p->moh);
528 ast_mutex_unlock(&p->chan->lock);
532 ast_mutex_unlock(&p->lock);
533 /* Release ownership of the agent to other threads (presumably running the login app). */
534 ast_mutex_unlock(&p->app_lock);
535 } else if (p->dead) {
536 /* Go ahead and lose it */
537 ast_mutex_unlock(&p->lock);
538 /* Release ownership of the agent to other threads (presumably running the login app). */
539 ast_mutex_unlock(&p->app_lock);
541 ast_mutex_unlock(&p->lock);
542 /* Release ownership of the agent to other threads (presumably running the login app). */
543 ast_mutex_unlock(&p->app_lock);
546 ast_mutex_unlock(&p->lock);
549 ast_mutex_lock(&agentlock);
551 ast_mutex_unlock(&agentlock);
553 if (p->abouttograb) {
554 /* Let the "about to grab" thread know this isn't valid anymore, and let it
557 } else if (p->dead) {
561 /* Not dead -- check availability now */
562 ast_mutex_lock(&p->lock);
563 /* Store last disconnect time */
564 gettimeofday(&p->lastdisc, NULL);
565 ast_mutex_unlock(&p->lock);
567 /* Release ownership of the agent to other threads (presumably running the login app). */
568 ast_mutex_unlock(&p->app_lock);
573 static int agent_cont_sleep( void *data )
579 p = (struct agent_pvt *)data;
581 ast_mutex_lock(&p->lock);
582 res = p->app_sleep_cond;
583 if (p->lastdisc.tv_sec) {
584 gettimeofday(&tv, NULL);
585 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
586 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
589 ast_mutex_unlock(&p->lock);
592 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
597 static int agent_ack_sleep( void *data )
604 /* Wait a second and look for something */
606 p = (struct agent_pvt *)data;
609 to = ast_waitfor(p->chan, to);
618 f = ast_read(p->chan);
623 if (f->frametype == AST_FRAME_DTMF)
628 ast_mutex_lock(&p->lock);
629 if (!p->app_sleep_cond) {
630 ast_mutex_unlock(&p->lock);
633 } else if (res == '#') {
634 ast_mutex_unlock(&p->lock);
638 ast_mutex_unlock(&p->lock);
646 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
648 struct ast_channel *tmp;
649 struct ast_frame null_frame = { AST_FRAME_NULL };
652 ast_log(LOG_WARNING, "No channel? :(\n");
656 tmp = ast_channel_alloc(0);
659 tmp->nativeformats = p->chan->nativeformats;
660 tmp->writeformat = p->chan->writeformat;
661 tmp->pvt->rawwriteformat = p->chan->writeformat;
662 tmp->readformat = p->chan->readformat;
663 tmp->pvt->rawreadformat = p->chan->readformat;
664 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
665 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
666 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
668 tmp->nativeformats = AST_FORMAT_SLINEAR;
669 tmp->writeformat = AST_FORMAT_SLINEAR;
670 tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
671 tmp->readformat = AST_FORMAT_SLINEAR;
672 tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
675 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
677 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
679 ast_setstate(tmp, state);
681 tmp->pvt->send_digit = agent_digit;
682 tmp->pvt->call = agent_call;
683 tmp->pvt->hangup = agent_hangup;
684 tmp->pvt->answer = agent_answer;
685 tmp->pvt->read = agent_read;
686 tmp->pvt->write = agent_write;
687 tmp->pvt->exception = agent_read;
688 tmp->pvt->indicate = agent_indicate;
689 tmp->pvt->fixup = agent_fixup;
691 ast_mutex_lock(&usecnt_lock);
693 ast_mutex_unlock(&usecnt_lock);
694 ast_update_use_count();
696 /* Wake up and wait for other applications (by definition the login app)
697 * to release this channel). Takes ownership of the agent channel
698 * to this thread only.
699 * For signalling the other thread, ast_queue_frame is used until we
700 * can safely use signals for this purpose. The pselect() needs to be
701 * implemented in the kernel for this.
703 p->app_sleep_cond = 0;
704 if( ast_mutex_trylock(&p->app_lock) )
707 ast_queue_frame(p->chan, &null_frame, 1);
708 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
709 ast_mutex_lock(&p->app_lock);
710 ast_mutex_lock(&p->lock);
714 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
716 tmp->pvt->pvt = NULL;
717 p->app_sleep_cond = 1;
718 ast_channel_free( tmp );
719 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
720 ast_mutex_unlock(&p->app_lock);
724 p->owning_app = pthread_self();
725 /* After the above step, there should not be any blockers. */
727 if (p->chan->blocking) {
728 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
731 ast_moh_stop(p->chan);
734 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
739 static int read_agent_config(void)
741 struct ast_config *cfg;
742 struct ast_variable *v;
743 struct agent_pvt *p, *pl, *pn;
748 cfg = ast_load(config);
750 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
753 ast_mutex_lock(&agentlock);
759 strcpy(moh, "default");
760 /* set the default recording values */
761 recordagentcalls = 0;
763 strcpy(recordformat, "wav");
764 strcpy(recordformatext, "wav");
765 strcpy(urlprefix, "");
766 strcpy(savecallsin, "");
768 v = ast_variable_browse(cfg, "agents");
770 /* Create the interface list */
771 if (!strcasecmp(v->name, "agent")) {
772 add_agent(v->value, 0);
773 } else if (!strcasecmp(v->name, "group")) {
774 group = ast_get_group(v->value);
775 } else if (!strcasecmp(v->name, "autologoff")) {
776 autologoff = atoi(v->value);
779 } else if (!strcasecmp(v->name, "ackcall")) {
780 if (!strcasecmp(v->value, "always"))
782 else if (ast_true(v->value))
786 } else if (!strcasecmp(v->name, "wrapuptime")) {
787 wrapuptime = atoi(v->value);
790 } else if (!strcasecmp(v->name, "musiconhold")) {
791 strncpy(moh, v->value, sizeof(moh) - 1);
792 } else if (!strcasecmp(v->name, "recordagentcalls")) {
793 recordagentcalls = ast_true(v->value);
794 } else if (!strcasecmp(v->name, "createlink")) {
795 createlink = ast_true(v->value);
796 } else if (!strcasecmp(v->name, "recordformat")) {
797 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
798 if (!strcasecmp(v->value, "wav49"))
799 strcpy(recordformatext, "WAV");
801 strncpy(recordformatext, v->value, sizeof(recordformat) - 1);
802 } else if (!strcasecmp(v->name, "urlprefix")) {
803 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
804 if (urlprefix[strlen(urlprefix) - 1] != '/')
805 strcat(urlprefix, "/");
806 } else if (!strcasecmp(v->name, "savecallsin")) {
807 if (v->value[0] == '/')
808 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
810 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
811 if (savecallsin[strlen(savecallsin) - 1] != '/')
812 strcat(savecallsin, "/");
826 /* Destroy if appropriate */
831 /* Cause them to hang up */
832 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
839 ast_mutex_unlock(&agentlock);
844 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
846 struct ast_channel *chan=NULL, *parent=NULL;
849 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
851 ast_mutex_lock(&agentlock);
854 if (p == newlyavailable) {
858 ast_mutex_lock(&p->lock);
859 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
860 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
861 /* We found a pending call, time to merge */
862 chan = agent_new(newlyavailable, AST_STATE_DOWN);
865 ast_mutex_unlock(&p->lock);
868 ast_mutex_unlock(&p->lock);
872 ast_mutex_unlock(&agentlock);
873 if (parent && chan) {
874 if (newlyavailable->ackcall > 1) {
875 /* Don't do beep here */
878 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
879 res = ast_streamfile(newlyavailable->chan, "beep", newlyavailable->chan->language);
880 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
882 res = ast_waitstream(newlyavailable->chan, "");
883 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
887 /* Note -- parent may have disappeared */
888 if (p->abouttograb) {
889 newlyavailable->acknowledged = 1;
890 ast_setstate(parent, AST_STATE_UP);
891 ast_setstate(chan, AST_STATE_UP);
892 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
893 /* Go ahead and mark the channel as a zombie so that masquerade will
894 destroy it for us, and we need not call ast_hangup */
895 ast_mutex_lock(&parent->lock);
897 ast_channel_masquerade(parent, chan);
898 ast_mutex_unlock(&parent->lock);
901 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
902 agent_cleanup(newlyavailable);
905 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
906 agent_cleanup(newlyavailable);
912 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
916 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
918 ast_mutex_lock(&agentlock);
921 if (p == newlyavailable) {
925 ast_mutex_lock(&p->lock);
926 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
927 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
928 ast_mutex_unlock(&p->lock);
931 ast_mutex_unlock(&p->lock);
935 ast_mutex_unlock(&agentlock);
937 ast_mutex_unlock(&newlyavailable->lock);
938 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
939 res = ast_streamfile(newlyavailable->chan, "beep", newlyavailable->chan->language);
940 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
942 res = ast_waitstream(newlyavailable->chan, "");
943 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
945 ast_mutex_lock(&newlyavailable->lock);
950 static struct ast_channel *agent_request(char *type, int format, void *data)
953 struct ast_channel *chan = NULL;
955 unsigned int groupmatch;
959 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
960 groupmatch = (1 << groupmatch);
961 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
962 groupmatch = (1 << groupmatch);
968 /* Check actual logged in agents first */
969 ast_mutex_lock(&agentlock);
972 ast_mutex_lock(&p->lock);
973 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
974 !strlen(p->loginchan)) {
977 if (!p->lastdisc.tv_sec) {
978 /* Agent must be registered, but not have any active call, and not be in a waiting state */
979 if (!p->owner && p->chan) {
981 chan = agent_new(p, AST_STATE_DOWN);
984 ast_mutex_unlock(&p->lock);
989 ast_mutex_unlock(&p->lock);
995 ast_mutex_lock(&p->lock);
996 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
997 if (p->chan || strlen(p->loginchan))
999 if (!p->lastdisc.tv_sec) {
1000 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1001 if (!p->owner && p->chan) {
1002 /* Could still get a fixed agent */
1003 chan = agent_new(p, AST_STATE_DOWN);
1004 } else if (!p->owner && strlen(p->loginchan)) {
1005 /* Adjustable agent */
1006 p->chan = ast_request("Local", format, p->loginchan);
1008 chan = agent_new(p, AST_STATE_DOWN);
1011 ast_mutex_unlock(&p->lock);
1016 ast_mutex_unlock(&p->lock);
1021 if (!chan && waitforagent) {
1022 /* No agent available -- but we're requesting to wait for one.
1023 Allocate a place holder */
1025 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1026 p = add_agent(data, 1);
1027 p->group = groupmatch;
1028 chan = agent_new(p, AST_STATE_DOWN);
1030 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1033 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1035 ast_mutex_unlock(&agentlock);
1039 static int powerof(unsigned int v)
1042 for (x=0;x<32;x++) {
1043 if (v & (1 << x)) return x;
1048 static int agents_show(int fd, int argc, char **argv)
1050 struct agent_pvt *p;
1051 char username[AST_MAX_BUF];
1052 char location[AST_MAX_BUF];
1053 char talkingto[AST_MAX_BUF];
1054 char moh[AST_MAX_BUF];
1057 return RESULT_SHOWUSAGE;
1058 ast_mutex_lock(&agentlock);
1061 ast_mutex_lock(&p->lock);
1064 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1066 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1068 if (strlen(p->name))
1069 snprintf(username, sizeof(username), "(%s) ", p->name);
1071 strcpy(username, "");
1073 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1074 if (p->owner && p->owner->bridge) {
1075 snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
1077 strcpy(talkingto, " is idle");
1079 } else if (strlen(p->loginchan)) {
1080 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1081 strcpy(talkingto, "");
1082 if (p->acknowledged)
1083 strcat(location, " (Confirmed)");
1085 strcpy(location, "not logged in");
1086 strcpy(talkingto, "");
1089 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1090 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1091 username, location, talkingto, moh);
1093 ast_mutex_unlock(&p->lock);
1096 ast_mutex_unlock(&agentlock);
1097 return RESULT_SUCCESS;
1100 static char show_agents_usage[] =
1101 "Usage: show agents\n"
1102 " Provides summary information on agents.\n";
1104 static struct ast_cli_entry cli_show_agents = {
1105 { "show", "agents", NULL }, agents_show,
1106 "Show status of agents", show_agents_usage, NULL };
1108 STANDARD_LOCAL_USER;
1111 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1115 struct agent_pvt *p;
1116 struct localuser *u;
1118 char user[AST_MAX_AGENT];
1119 char pass[AST_MAX_AGENT];
1120 char xpass[AST_MAX_AGENT] = "";
1123 char *opt_user = NULL;
1124 char *options = NULL;
1125 char *context = NULL;
1127 int play_announcement;
1128 char *filename = "agent-loginok";
1132 /* Parse the arguments XXX Check for failure XXX */
1133 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1136 options = strchr(opt_user, '|');
1141 context = strchr(options, '@');
1147 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1154 if (chan->_state != AST_STATE_UP)
1155 res = ast_answer(chan);
1157 if( opt_user && strlen(opt_user))
1158 strncpy( user, opt_user, AST_MAX_AGENT );
1160 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1162 while (!res && (tries < 3)) {
1163 /* Check for password */
1164 ast_mutex_lock(&agentlock);
1167 if (!strcmp(p->agent, user) && !p->pending)
1168 strncpy(xpass, p->password, sizeof(xpass) - 1);
1171 ast_mutex_unlock(&agentlock);
1174 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1178 errmsg = "agent-incorrect";
1181 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1184 /* Check again for accuracy */
1185 ast_mutex_lock(&agentlock);
1188 ast_mutex_lock(&p->lock);
1189 if (!strcmp(p->agent, user) &&
1190 !strcmp(p->password, pass) && !p->pending) {
1193 char tmpchan[AST_MAX_BUF] = "";
1195 /* Retrieve login chan */
1198 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1201 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1202 if (!strlen(tmpchan) || ast_exists_extension(chan, context && strlen(context) ? context : "default", tmpchan,
1206 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1210 res = ast_streamfile(chan, "invalid", chan->language);
1212 res = ast_waitstream(chan, AST_DIGIT_ANY);
1224 if (context && strlen(context) && strlen(tmpchan))
1225 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1227 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1228 if (!strlen(p->loginchan))
1229 filename = "agent-loggedoff";
1230 p->acknowledged = 0;
1231 /* clear the global variable that stores agentid based on the callerid */
1232 if (chan->callerid) {
1233 char agentvar[AST_MAX_BUF];
1234 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->callerid);
1235 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1239 strcpy(p->loginchan, "");
1240 p->acknowledged = 0;
1242 play_announcement = 1;
1244 if( strchr( options, 's' ) )
1245 play_announcement = 0;
1246 ast_mutex_unlock(&p->lock);
1247 ast_mutex_unlock(&agentlock);
1248 if( !res && play_announcement )
1249 res = ast_streamfile(chan, filename, chan->language);
1251 ast_waitstream(chan, "");
1252 ast_mutex_lock(&agentlock);
1253 ast_mutex_lock(&p->lock);
1255 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1257 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1260 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1262 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1264 /* Check once more just in case */
1267 if (callbackmode && !res) {
1268 /* Just say goodbye and be done with it */
1269 ast_mutex_unlock(&agentlock);
1271 res = ast_safe_sleep(chan, 500);
1272 res = ast_streamfile(chan, "vm-goodbye", chan->language);
1274 res = ast_waitstream(chan, "");
1276 res = ast_safe_sleep(chan, 1000);
1277 /* store agent id based on the callerid as a global variable */
1278 if (chan->callerid) {
1279 char agentvar[AST_MAX_BUF];
1280 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->callerid);
1281 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1283 ast_mutex_unlock(&p->lock);
1285 #ifdef HONOR_MUSIC_CLASS
1286 /* check if the moh class was changed with setmusiconhold */
1287 if (*(chan->musicclass))
1288 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1290 ast_moh_start(chan, p->moh);
1291 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1294 p->agent, chan->name);
1295 if (option_verbose > 2)
1296 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1297 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1298 /* Login this channel and wait for it to
1304 check_availability(p, 0);
1305 ast_mutex_unlock(&p->lock);
1306 ast_mutex_unlock(&agentlock);
1308 ast_mutex_lock(&p->lock);
1309 if (p->chan != chan)
1311 ast_mutex_unlock(&p->lock);
1312 /* Yield here so other interested threads can kick in. */
1317 ast_mutex_lock(&agentlock);
1318 ast_mutex_lock(&p->lock);
1319 if (p->lastdisc.tv_sec) {
1320 gettimeofday(&tv, NULL);
1321 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1322 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1323 ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1324 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1328 check_availability(p, 0);
1331 ast_mutex_unlock(&p->lock);
1332 ast_mutex_unlock(&agentlock);
1333 /* Synchronize channel ownership between call to agent and itself. */
1334 ast_mutex_lock( &p->app_lock );
1335 ast_mutex_lock(&p->lock);
1336 p->owning_app = pthread_self();
1337 ast_mutex_unlock(&p->lock);
1339 res = agent_ack_sleep(p);
1341 res = ast_safe_sleep_conditional( chan, 1000,
1342 agent_cont_sleep, p );
1343 ast_mutex_unlock( &p->app_lock );
1344 if ((p->ackcall > 1) && (res == 1)) {
1345 ast_mutex_lock(&agentlock);
1346 ast_mutex_lock(&p->lock);
1347 check_availability(p, 0);
1348 ast_mutex_unlock(&p->lock);
1349 ast_mutex_unlock(&agentlock);
1354 ast_mutex_lock(&p->lock);
1355 if (res && p->owner)
1356 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1357 /* Log us off if appropriate */
1358 if (p->chan == chan)
1360 p->acknowledged = 0;
1361 ast_mutex_unlock(&p->lock);
1362 if (option_verbose > 2)
1363 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1364 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1367 /* If there is no owner, go ahead and kill it now */
1368 if (p->dead && !p->owner)
1372 ast_mutex_unlock(&p->lock);
1377 ast_mutex_unlock(&p->lock);
1378 errmsg = "agent-alreadyon";
1383 ast_mutex_unlock(&p->lock);
1387 ast_mutex_unlock(&agentlock);
1390 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1393 LOCAL_USER_REMOVE(u);
1398 static int login_exec(struct ast_channel *chan, void *data)
1400 return __login_exec(chan, data, 0);
1403 static int callback_exec(struct ast_channel *chan, void *data)
1405 return __login_exec(chan, data, 1);
1408 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1410 int exitifnoagentid = 0;
1414 char agent[AST_MAX_AGENT], *tmp;
1416 if (strchr(data, 'd'))
1417 exitifnoagentid = 1;
1418 if (strchr(data, 'n'))
1420 if (strchr(data, 'c'))
1423 if (chan->callerid) {
1424 char agentvar[AST_MAX_BUF];
1425 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->callerid);
1426 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1427 struct agent_pvt *p = agents;
1428 strncpy(agent, tmp, sizeof(agent) - 1);
1429 ast_mutex_lock(&agentlock);
1431 if (!strcasecmp(p->agent, tmp)) {
1432 __agent_start_monitoring(chan, p, 1);
1433 if (updatecdr && chan->cdr) {
1434 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1440 ast_mutex_unlock(&agentlock);
1445 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);
1450 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");
1452 /* check if there is n + 101 priority */
1454 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
1455 chan->priority+=100;
1456 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1458 else if (exitifnoagentid)
1466 /* Make sure we can register our sip channel type */
1467 if (ast_channel_register(type, tdesc, capability, agent_request)) {
1468 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1471 ast_register_application(app, login_exec, synopsis, descrip);
1472 ast_register_application(app2, callback_exec, synopsis2, descrip2);
1473 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1474 ast_cli_register(&cli_show_agents);
1475 /* Read in the config */
1476 read_agent_config();
1482 read_agent_config();
1488 struct agent_pvt *p;
1489 /* First, take us out of the channel loop */
1490 ast_cli_unregister(&cli_show_agents);
1491 ast_unregister_application(app);
1492 ast_unregister_application(app2);
1493 ast_unregister_application(app3);
1494 ast_channel_unregister(type);
1495 if (!ast_mutex_lock(&agentlock)) {
1496 /* Hangup all interfaces if they have an owner */
1500 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1504 ast_mutex_unlock(&agentlock);
1506 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1515 ast_mutex_lock(&usecnt_lock);
1517 ast_mutex_unlock(&usecnt_lock);
1523 return ASTERISK_GPL_KEY;