2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Agents
6 * Copyright (C) 1999-2004, Digium Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
16 #include <asterisk/lock.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/channel_pvt.h>
19 #include <asterisk/config.h>
20 #include <asterisk/logger.h>
21 #include <asterisk/module.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/options.h>
24 #include <asterisk/lock.h>
25 #include <asterisk/sched.h>
26 #include <asterisk/io.h>
27 #include <asterisk/rtp.h>
28 #include <asterisk/acl.h>
29 #include <asterisk/callerid.h>
30 #include <asterisk/file.h>
31 #include <asterisk/cli.h>
32 #include <asterisk/app.h>
33 #include <asterisk/musiconhold.h>
34 #include <asterisk/manager.h>
35 #include <asterisk/features.h>
36 #include <asterisk/utils.h>
37 #include <asterisk/causes.h>
38 #include <sys/socket.h>
44 #include <arpa/inet.h>
45 #include <sys/signal.h>
47 static char *desc = "Agent Proxy Channel";
48 static char *type = "Agent";
49 static char *tdesc = "Call Agent Proxy Channel";
50 static char *config = "agents.conf";
52 static char *app = "AgentLogin";
53 static char *app2 = "AgentCallbackLogin";
54 static char *app3 = "AgentMonitorOutgoing";
56 static char *synopsis = "Call agent login";
57 static char *synopsis2 = "Call agent callback login";
58 static char *synopsis3 = "Record agent's outgoing call";
60 static char *descrip =
61 " AgentLogin([AgentNo][|options]):\n"
62 "Asks the agent to login to the system. Always returns -1. While\n"
63 "logged in, the agent can receive calls and will hear a 'beep'\n"
64 "when a new call comes in. The agent can dump the call by pressing\n"
66 "The option string may contain zero or more of the following characters:\n"
67 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
69 static char *descrip2 =
70 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
71 "Asks the agent to login to the system with callback.\n"
72 "The agent's callback extension is called (optionally with the specified\n"
74 "The option string may contain zero or more of the following characters:\n"
75 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
79 static char *descrip3 =
80 " AgentMonitorOutgoing([options]):\n"
81 "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"
82 " 'd' - make the app return -1 if there is an error condition and there is no extension n+101\n"
83 " '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";
85 static char mandescr_agents[] =
86 "Description: Will list info about all possible agents.\n"
89 static char moh[80] = "default";
91 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
92 #define AST_MAX_BUF 256
93 #define AST_MAX_FILENAME_LEN 256
95 static int capability = -1;
97 static unsigned int group;
98 static int autologoff;
99 static int wrapuptime;
102 static int maxlogintries = 3;
103 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
105 static int usecnt =0;
106 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
108 /* Protect the interface list (of sip_pvt's) */
109 AST_MUTEX_DEFINE_STATIC(agentlock);
111 static int recordagentcalls = 0;
112 static char recordformat[AST_MAX_BUF] = "";
113 static char recordformatext[AST_MAX_BUF] = "";
114 static int createlink = 0;
115 static char urlprefix[AST_MAX_BUF] = "";
116 static char savecallsin[AST_MAX_BUF] = "";
117 static int updatecdr = 0;
118 static char beep[AST_MAX_BUF] = "beep";
120 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
122 static struct agent_pvt {
123 ast_mutex_t lock; /* Channel private lock */
124 int dead; /* Poised for destruction? */
125 int pending; /* Not a real agent -- just pending a match */
126 int abouttograb; /* About to grab */
127 int autologoff; /* Auto timeout time */
128 int ackcall; /* ackcall */
129 time_t loginstart; /* When agent first logged in (0 when logged off) */
130 time_t start; /* When call started */
131 struct timeval lastdisc; /* When last disconnected */
132 int wrapuptime; /* Wrapup time in ms */
133 unsigned int group; /* Group memberships */
134 int acknowledged; /* Acknowledged */
135 char moh[80]; /* Which music on hold */
136 char agent[AST_MAX_AGENT]; /* Agent ID */
137 char password[AST_MAX_AGENT]; /* Password for Agent login */
138 char name[AST_MAX_AGENT];
139 ast_mutex_t app_lock; /* Synchronization between owning applications */
140 volatile pthread_t owning_app; /* Owning application thread id */
141 volatile int app_sleep_cond; /* Sleep condition for the login app */
142 struct ast_channel *owner; /* Agent */
144 struct ast_channel *chan; /* Channel we use */
145 struct agent_pvt *next; /* Agent */
148 #define CHECK_FORMATS(ast, p) do { \
150 if (ast->nativeformats != p->chan->nativeformats) { \
151 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
152 /* Native formats changed, reset things */ \
153 ast->nativeformats = p->chan->nativeformats; \
154 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
155 ast_set_read_format(ast, ast->readformat); \
156 ast_set_write_format(ast, ast->writeformat); \
158 if (p->chan->readformat != ast->pvt->rawreadformat) \
159 ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
160 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
161 ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
165 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
166 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
167 totally impractical combinations XXX */
169 #define CLEANUP(ast, p) do { \
172 for (x=0;x<AST_MAX_FDS;x++) {\
173 if (x != AST_MAX_FDS - 2) \
174 ast->fds[x] = p->chan->fds[x]; \
176 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
181 static void agent_unlink(struct agent_pvt *agent)
183 struct agent_pvt *p, *prev;
189 prev->next = agent->next;
191 agents = agent->next;
199 static struct agent_pvt *add_agent(char *agent, int pending)
201 char tmp[AST_MAX_BUF] = "";
202 char *password=NULL, *name=NULL;
203 struct agent_pvt *p, *prev;
205 strncpy(tmp, agent, sizeof(tmp) - 1);
206 if ((password = strchr(tmp, ','))) {
209 while (*password < 33) password++;
211 if (password && (name = strchr(password, ','))) {
214 while (*name < 33) name++;
219 if (!pending && !strcmp(p->agent, tmp))
225 p = malloc(sizeof(struct agent_pvt));
227 memset(p, 0, sizeof(struct agent_pvt));
228 strncpy(p->agent, tmp, sizeof(p->agent) -1);
229 ast_mutex_init(&p->lock);
230 ast_mutex_init(&p->app_lock);
231 p->owning_app = (pthread_t) -1;
232 p->app_sleep_cond = 1;
234 p->pending = pending;
245 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
246 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
247 strncpy(p->moh, moh, sizeof(p->moh) - 1);
248 p->ackcall = ackcall;
249 p->autologoff = autologoff;
250 p->wrapuptime = wrapuptime;
258 static int agent_cleanup(struct agent_pvt *p)
260 struct ast_channel *chan = p->owner;
262 chan->pvt->pvt = NULL;
263 p->app_sleep_cond = 1;
264 /* Release ownership of the agent to other threads (presumably running the login app). */
265 ast_mutex_unlock(&p->app_lock);
267 ast_channel_free(chan);
269 ast_mutex_destroy(&p->lock);
270 ast_mutex_destroy(&p->app_lock);
276 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
278 static int agent_answer(struct ast_channel *ast)
280 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
284 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
286 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
287 char filename[AST_MAX_BUF];
292 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
293 /* substitute . for - */
294 if ((pointer = strchr(filename, '.')))
296 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
297 ast_monitor_start(ast, recordformat, tmp, needlock);
298 ast_monitor_setjoinfiles(ast, 1);
299 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
301 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
304 ast->cdr = ast_cdr_alloc();
305 ast_cdr_setuserfield(ast, tmp2);
308 ast_log(LOG_ERROR, "Recording already started on that call.\n");
312 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
314 return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
317 static struct ast_frame *agent_read(struct ast_channel *ast)
319 struct agent_pvt *p = ast->pvt->pvt;
320 struct ast_frame *f = NULL;
321 static struct ast_frame null_frame = { AST_FRAME_NULL, };
322 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
323 ast_mutex_lock(&p->lock);
324 CHECK_FORMATS(ast, p);
326 p->chan->exception = ast->exception;
327 if (ast->fdno == AST_MAX_FDS - 3)
328 p->chan->fdno = AST_MAX_FDS - 2;
330 p->chan->fdno = ast->fdno;
331 f = ast_read(p->chan);
335 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
337 /* Note that we don't hangup if it's not a callback because Asterisk will do it
338 for us when the PBX instance that called login finishes */
339 if (!ast_strlen_zero(p->loginchan)) {
340 p->chan->_bridge = NULL;
343 gettimeofday(&p->lastdisc, NULL);
344 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
345 if (p->lastdisc.tv_usec > 1000000) {
346 p->lastdisc.tv_usec -= 1000000;
347 p->lastdisc.tv_sec++;
349 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
356 if (f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
359 if (option_verbose > 2)
360 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
361 /* Don't pass answer along */
369 p->chan->_bridge = ast;
373 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
374 if (!p->acknowledged) {
375 if (option_verbose > 2)
376 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
381 p->chan->_bridge = ast;
384 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
385 /* * terminates call */
390 ast_mutex_unlock(&p->lock);
391 if (recordagentcalls && f == &answer_frame)
392 agent_start_monitoring(ast,0);
396 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
398 struct agent_pvt *p = ast->pvt->pvt;
400 CHECK_FORMATS(ast, p);
401 ast_mutex_lock(&p->lock);
403 if ((f->frametype != AST_FRAME_VOICE) ||
404 (f->subclass == p->chan->writeformat)) {
405 res = ast_write(p->chan, f);
407 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
413 ast_mutex_unlock(&p->lock);
417 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
419 struct agent_pvt *p = newchan->pvt->pvt;
420 ast_mutex_lock(&p->lock);
421 if (p->owner != oldchan) {
422 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
423 ast_mutex_unlock(&p->lock);
427 ast_mutex_unlock(&p->lock);
431 static int agent_indicate(struct ast_channel *ast, int condition)
433 struct agent_pvt *p = ast->pvt->pvt;
435 ast_mutex_lock(&p->lock);
437 res = ast_indicate(p->chan, condition);
440 ast_mutex_unlock(&p->lock);
444 static int agent_digit(struct ast_channel *ast, char digit)
446 struct agent_pvt *p = ast->pvt->pvt;
448 ast_mutex_lock(&p->lock);
450 res = p->chan->pvt->send_digit(p->chan, digit);
453 ast_mutex_unlock(&p->lock);
457 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
459 struct agent_pvt *p = ast->pvt->pvt;
461 ast_mutex_lock(&p->lock);
465 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
466 ast_setstate(ast, AST_STATE_DIALING);
469 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
472 ast_mutex_unlock(&p->lock);
474 } else if (!ast_strlen_zero(p->loginchan)) {
476 /* Call on this agent */
477 if (option_verbose > 2)
478 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
479 if (p->chan->cid.cid_num)
480 free(p->chan->cid.cid_num);
481 if (ast->cid.cid_num)
482 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
484 p->chan->cid.cid_num = NULL;
485 if (p->chan->cid.cid_name)
486 free(p->chan->cid.cid_name);
487 if (ast->cid.cid_name)
488 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
490 p->chan->cid.cid_name = NULL;
491 res = ast_call(p->chan, p->loginchan, 0);
493 ast_mutex_unlock(&p->lock);
496 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
497 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
498 res = ast_streamfile(p->chan, beep, p->chan->language);
499 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
501 res = ast_waitstream(p->chan, "");
502 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
505 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
506 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
508 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
515 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
516 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
518 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
522 /* Call is immediately up, or might need ack */
524 ast_setstate(ast, AST_STATE_RINGING);
526 ast_setstate(ast, AST_STATE_UP);
527 if (recordagentcalls)
528 agent_start_monitoring(ast,0);
534 ast_mutex_unlock(&p->lock);
538 static int agent_hangup(struct ast_channel *ast)
540 struct agent_pvt *p = ast->pvt->pvt;
542 ast_mutex_lock(&p->lock);
544 ast->pvt->pvt = NULL;
545 p->app_sleep_cond = 1;
548 /* if they really are hung up then set start to 0 so the test
549 * later if we're called on an already downed channel
550 * doesn't cause an agent to be logged out like when
551 * agent_request() is followed immediately by agent_hangup()
552 * as in apps/app_chanisavail.c:chanavail_exec()
555 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
556 if (p->start && (ast->_state != AST_STATE_UP)) {
557 howlong = time(NULL) - p->start;
559 } else if (ast->_state == AST_STATE_RESERVED) {
564 /* If they're dead, go ahead and hang up on the agent now */
565 if (!ast_strlen_zero(p->loginchan)) {
566 /* Store last disconnect time */
568 gettimeofday(&p->lastdisc, NULL);
569 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
570 if (p->lastdisc.tv_usec >= 1000000) {
571 p->lastdisc.tv_usec -= 1000000;
572 p->lastdisc.tv_sec++;
574 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
576 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
578 /* Recognize the hangup and pass it along immediately */
582 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
583 if (howlong && p->autologoff && (howlong > p->autologoff)) {
584 char agent[AST_MAX_AGENT] = "";
585 long logintime = time(NULL) - p->loginstart;
587 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
588 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
592 "Reason: Autologoff\r\n"
594 p->agent, p->loginchan, logintime, ast->uniqueid);
595 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
596 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
597 p->loginchan[0] = '\0';
598 ast_device_state_changed("Agent/%s", p->agent);
600 } else if (p->dead) {
601 ast_mutex_lock(&p->chan->lock);
602 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
603 ast_mutex_unlock(&p->chan->lock);
605 ast_mutex_lock(&p->chan->lock);
606 ast_moh_start(p->chan, p->moh);
607 ast_mutex_unlock(&p->chan->lock);
611 ast_mutex_unlock(&p->lock);
612 /* Release ownership of the agent to other threads (presumably running the login app). */
613 ast_mutex_unlock(&p->app_lock);
614 } else if (p->dead) {
615 /* Go ahead and lose it */
616 ast_mutex_unlock(&p->lock);
617 /* Release ownership of the agent to other threads (presumably running the login app). */
618 ast_mutex_unlock(&p->app_lock);
620 ast_mutex_unlock(&p->lock);
621 /* Release ownership of the agent to other threads (presumably running the login app). */
622 ast_mutex_unlock(&p->app_lock);
625 ast_mutex_unlock(&p->lock);
628 ast_mutex_lock(&agentlock);
630 ast_mutex_unlock(&agentlock);
632 if (p->abouttograb) {
633 /* Let the "about to grab" thread know this isn't valid anymore, and let it
636 } else if (p->dead) {
637 ast_mutex_destroy(&p->lock);
638 ast_mutex_destroy(&p->app_lock);
642 /* Not dead -- check availability now */
643 ast_mutex_lock(&p->lock);
644 /* Store last disconnect time */
645 gettimeofday(&p->lastdisc, NULL);
646 ast_mutex_unlock(&p->lock);
648 /* Release ownership of the agent to other threads (presumably running the login app). */
649 ast_mutex_unlock(&p->app_lock);
654 static int agent_cont_sleep( void *data )
660 p = (struct agent_pvt *)data;
662 ast_mutex_lock(&p->lock);
663 res = p->app_sleep_cond;
664 if (p->lastdisc.tv_sec) {
665 gettimeofday(&tv, NULL);
666 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
667 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
670 ast_mutex_unlock(&p->lock);
673 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
678 static int agent_ack_sleep( void *data )
685 /* Wait a second and look for something */
687 p = (struct agent_pvt *)data;
690 to = ast_waitfor(p->chan, to);
699 f = ast_read(p->chan);
704 if (f->frametype == AST_FRAME_DTMF)
709 ast_mutex_lock(&p->lock);
710 if (!p->app_sleep_cond) {
711 ast_mutex_unlock(&p->lock);
714 } else if (res == '#') {
715 ast_mutex_unlock(&p->lock);
719 ast_mutex_unlock(&p->lock);
727 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
730 struct ast_channel *ret=NULL;
732 p = bridge->pvt->pvt;
734 ret = bridge->_bridge;
735 else if (chan == bridge->_bridge)
740 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
742 struct ast_channel *tmp;
743 struct ast_frame null_frame = { AST_FRAME_NULL };
746 ast_log(LOG_WARNING, "No channel? :(\n");
750 tmp = ast_channel_alloc(0);
753 tmp->nativeformats = p->chan->nativeformats;
754 tmp->writeformat = p->chan->writeformat;
755 tmp->pvt->rawwriteformat = p->chan->writeformat;
756 tmp->readformat = p->chan->readformat;
757 tmp->pvt->rawreadformat = p->chan->readformat;
758 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
759 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
760 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
762 tmp->nativeformats = AST_FORMAT_SLINEAR;
763 tmp->writeformat = AST_FORMAT_SLINEAR;
764 tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
765 tmp->readformat = AST_FORMAT_SLINEAR;
766 tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
769 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
771 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
773 ast_setstate(tmp, state);
775 tmp->pvt->send_digit = agent_digit;
776 tmp->pvt->call = agent_call;
777 tmp->pvt->hangup = agent_hangup;
778 tmp->pvt->answer = agent_answer;
779 tmp->pvt->read = agent_read;
780 tmp->pvt->write = agent_write;
781 tmp->pvt->exception = agent_read;
782 tmp->pvt->indicate = agent_indicate;
783 tmp->pvt->fixup = agent_fixup;
784 tmp->pvt->bridged_channel = agent_bridgedchannel;
786 ast_mutex_lock(&usecnt_lock);
788 ast_mutex_unlock(&usecnt_lock);
789 ast_update_use_count();
791 /* Wake up and wait for other applications (by definition the login app)
792 * to release this channel). Takes ownership of the agent channel
793 * to this thread only.
794 * For signalling the other thread, ast_queue_frame is used until we
795 * can safely use signals for this purpose. The pselect() needs to be
796 * implemented in the kernel for this.
798 p->app_sleep_cond = 0;
799 if( ast_mutex_trylock(&p->app_lock) )
802 ast_queue_frame(p->chan, &null_frame);
803 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
804 ast_mutex_lock(&p->app_lock);
805 ast_mutex_lock(&p->lock);
809 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
811 tmp->pvt->pvt = NULL;
812 p->app_sleep_cond = 1;
813 ast_channel_free( tmp );
814 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
815 ast_mutex_unlock(&p->app_lock);
819 p->owning_app = pthread_self();
820 /* After the above step, there should not be any blockers. */
822 if (p->chan->blocking) {
823 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
826 ast_moh_stop(p->chan);
829 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
834 static int read_agent_config(void)
836 struct ast_config *cfg;
837 struct ast_variable *v;
838 struct agent_pvt *p, *pl, *pn;
843 cfg = ast_load(config);
845 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
848 ast_mutex_lock(&agentlock);
854 strncpy(moh, "default", sizeof(moh) - 1);
855 /* set the default recording values */
856 recordagentcalls = 0;
858 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
859 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
861 savecallsin[0] = '\0';
863 v = ast_variable_browse(cfg, "agents");
865 /* Create the interface list */
866 if (!strcasecmp(v->name, "agent")) {
867 add_agent(v->value, 0);
868 } else if (!strcasecmp(v->name, "group")) {
869 group = ast_get_group(v->value);
870 } else if (!strcasecmp(v->name, "autologoff")) {
871 autologoff = atoi(v->value);
874 } else if (!strcasecmp(v->name, "ackcall")) {
875 if (!strcasecmp(v->value, "always"))
877 else if (ast_true(v->value))
881 } else if (!strcasecmp(v->name, "wrapuptime")) {
882 wrapuptime = atoi(v->value);
885 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
886 maxlogintries = atoi(v->value);
887 if (maxlogintries < 0)
889 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
890 strcpy(agentgoodbye,v->value);
891 } else if (!strcasecmp(v->name, "musiconhold")) {
892 strncpy(moh, v->value, sizeof(moh) - 1);
893 } else if (!strcasecmp(v->name, "updatecdr")) {
894 if (ast_true(v->value))
898 } else if (!strcasecmp(v->name, "recordagentcalls")) {
899 recordagentcalls = ast_true(v->value);
900 } else if (!strcasecmp(v->name, "createlink")) {
901 createlink = ast_true(v->value);
902 } else if (!strcasecmp(v->name, "recordformat")) {
903 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
904 if (!strcasecmp(v->value, "wav49"))
905 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
907 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
908 } else if (!strcasecmp(v->name, "urlprefix")) {
909 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
910 if (urlprefix[strlen(urlprefix) - 1] != '/')
911 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
912 } else if (!strcasecmp(v->name, "savecallsin")) {
913 if (v->value[0] == '/')
914 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
916 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
917 if (savecallsin[strlen(savecallsin) - 1] != '/')
918 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
919 } else if (!strcasecmp(v->name, "custom_beep")) {
920 strncpy(beep, v->value, sizeof(beep) - 1);
934 /* Destroy if appropriate */
937 ast_mutex_destroy(&p->lock);
938 ast_mutex_destroy(&p->app_lock);
941 /* Cause them to hang up */
942 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
949 ast_mutex_unlock(&agentlock);
954 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
956 struct ast_channel *chan=NULL, *parent=NULL;
959 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
961 ast_mutex_lock(&agentlock);
964 if (p == newlyavailable) {
968 ast_mutex_lock(&p->lock);
969 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
970 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
971 /* We found a pending call, time to merge */
972 chan = agent_new(newlyavailable, AST_STATE_DOWN);
975 ast_mutex_unlock(&p->lock);
978 ast_mutex_unlock(&p->lock);
982 ast_mutex_unlock(&agentlock);
983 if (parent && chan) {
984 if (newlyavailable->ackcall > 1) {
985 /* Don't do beep here */
988 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
989 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
990 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
992 res = ast_waitstream(newlyavailable->chan, "");
993 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
997 /* Note -- parent may have disappeared */
998 if (p->abouttograb) {
999 newlyavailable->acknowledged = 1;
1000 ast_setstate(parent, AST_STATE_UP);
1001 ast_setstate(chan, AST_STATE_UP);
1002 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1003 /* Go ahead and mark the channel as a zombie so that masquerade will
1004 destroy it for us, and we need not call ast_hangup */
1005 ast_mutex_lock(&parent->lock);
1007 ast_channel_masquerade(parent, chan);
1008 ast_mutex_unlock(&parent->lock);
1011 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1012 agent_cleanup(newlyavailable);
1015 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1016 agent_cleanup(newlyavailable);
1022 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1024 struct agent_pvt *p;
1026 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1028 ast_mutex_lock(&agentlock);
1031 if (p == newlyavailable) {
1035 ast_mutex_lock(&p->lock);
1036 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1037 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1038 ast_mutex_unlock(&p->lock);
1041 ast_mutex_unlock(&p->lock);
1045 ast_mutex_unlock(&agentlock);
1047 ast_mutex_unlock(&newlyavailable->lock);
1048 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1049 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1050 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1052 res = ast_waitstream(newlyavailable->chan, "");
1053 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1055 ast_mutex_lock(&newlyavailable->lock);
1060 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1062 struct agent_pvt *p;
1063 struct ast_channel *chan = NULL;
1065 unsigned int groupmatch;
1070 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1071 groupmatch = (1 << groupmatch);
1072 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1073 groupmatch = (1 << groupmatch);
1079 /* Check actual logged in agents first */
1080 ast_mutex_lock(&agentlock);
1083 ast_mutex_lock(&p->lock);
1084 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1085 ast_strlen_zero(p->loginchan)) {
1088 if (!p->lastdisc.tv_sec) {
1089 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1090 if (!p->owner && p->chan) {
1092 chan = agent_new(p, AST_STATE_DOWN);
1095 ast_mutex_unlock(&p->lock);
1100 ast_mutex_unlock(&p->lock);
1106 ast_mutex_lock(&p->lock);
1107 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1108 if (p->chan || !ast_strlen_zero(p->loginchan))
1110 gettimeofday(&tv, NULL);
1112 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1114 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1115 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1116 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1117 if (!p->owner && p->chan) {
1118 /* Could still get a fixed agent */
1119 chan = agent_new(p, AST_STATE_DOWN);
1120 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1121 /* Adjustable agent */
1122 p->chan = ast_request("Local", format, p->loginchan, cause);
1124 chan = agent_new(p, AST_STATE_DOWN);
1127 ast_mutex_unlock(&p->lock);
1132 ast_mutex_unlock(&p->lock);
1137 if (!chan && waitforagent) {
1138 /* No agent available -- but we're requesting to wait for one.
1139 Allocate a place holder */
1141 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1142 p = add_agent(data, 1);
1143 p->group = groupmatch;
1144 chan = agent_new(p, AST_STATE_DOWN);
1146 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1149 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1152 *cause = AST_CAUSE_BUSY;
1154 *cause = AST_CAUSE_UNREGISTERED;
1155 ast_mutex_unlock(&agentlock);
1159 static int powerof(unsigned int v)
1162 for (x=0;x<32;x++) {
1163 if (v & (1 << x)) return x;
1168 static int action_agents(struct mansession *s, struct message *m)
1170 struct agent_pvt *p;
1171 char *username = NULL;
1172 char *loginChan = NULL;
1173 char *talkingtoChan = NULL;
1174 char *status = NULL;
1175 ast_mutex_lock(&agentlock);
1178 ast_mutex_lock(&p->lock);
1180 /* Status Values: AGENT_LOGGEDOFF - Agent isn't logged in
1181 AGENT_IDLE - Agent is logged in, and waiting for call
1182 AGENT_ONCALL - Agent is logged in, and on a call
1183 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1185 if(!ast_strlen_zero(p->name)) {
1191 /* Set a default status. It 'should' get changed. */
1192 status = "AGENT_UNKNOWN";
1195 loginChan = p->loginchan;
1196 if(p->owner && p->owner->_bridge) {
1197 talkingtoChan = p->chan->cid.cid_num;
1198 status = "AGENT_ONCALL";
1200 talkingtoChan = "n/a";
1201 status = "AGENT_IDLE";
1203 } else if(!ast_strlen_zero(p->loginchan)) {
1204 loginChan = p->loginchan;
1205 talkingtoChan = "n/a";
1206 status = "AGENT_IDLE";
1207 if(p->acknowledged) {
1208 sprintf(loginChan, " %s (Confirmed)", loginChan);
1212 talkingtoChan = "n/a";
1213 status = "AGENT_LOGGEDOFF";
1216 ast_cli(s->fd, "Event: Agents\r\n"
1220 "LoggedInChan: %s\r\n"
1221 "LoggedInTime: %ld\r\n"
1224 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1225 ast_mutex_unlock(&p->lock);
1228 ast_mutex_unlock(&agentlock);
1233 static int agents_show(int fd, int argc, char **argv)
1235 struct agent_pvt *p;
1236 char username[AST_MAX_BUF];
1237 char location[AST_MAX_BUF] = "";
1238 char talkingto[AST_MAX_BUF] = "";
1239 char moh[AST_MAX_BUF];
1242 return RESULT_SHOWUSAGE;
1243 ast_mutex_lock(&agentlock);
1246 ast_mutex_lock(&p->lock);
1249 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1251 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1253 if (!ast_strlen_zero(p->name))
1254 snprintf(username, sizeof(username), "(%s) ", p->name);
1258 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1259 if (p->owner && ast_bridged_channel(p->owner)) {
1260 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1262 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1264 } else if (!ast_strlen_zero(p->loginchan)) {
1265 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1266 talkingto[0] = '\0';
1267 if (p->acknowledged)
1268 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1270 strncpy(location, "not logged in", sizeof(location) - 1);
1271 talkingto[0] = '\0';
1273 if (!ast_strlen_zero(p->moh))
1274 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1275 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1276 username, location, talkingto, moh);
1278 ast_mutex_unlock(&p->lock);
1281 ast_mutex_unlock(&agentlock);
1282 return RESULT_SUCCESS;
1285 static char show_agents_usage[] =
1286 "Usage: show agents\n"
1287 " Provides summary information on agents.\n";
1289 static struct ast_cli_entry cli_show_agents = {
1290 { "show", "agents", NULL }, agents_show,
1291 "Show status of agents", show_agents_usage, NULL };
1293 STANDARD_LOCAL_USER;
1296 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1300 int max_login_tries = maxlogintries;
1301 struct agent_pvt *p;
1302 struct localuser *u;
1304 int login_state = 0;
1305 char user[AST_MAX_AGENT] = "";
1306 char pass[AST_MAX_AGENT];
1307 char agent[AST_MAX_AGENT] = "";
1308 char xpass[AST_MAX_AGENT] = "";
1311 char *opt_user = NULL;
1312 char *options = NULL;
1315 char *tmpoptions = NULL;
1316 char *context = NULL;
1318 int play_announcement = 1;
1319 char agent_goodbye[AST_MAX_FILENAME_LEN];
1320 int update_cdr = updatecdr;
1321 char *filename = "agent-loginok";
1323 strcpy(agent_goodbye, agentgoodbye);
1326 /* Parse the arguments XXX Check for failure XXX */
1327 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1329 /* Set Channel Specific Login Overrides */
1330 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1331 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1332 if (max_login_tries < 0)
1333 max_login_tries = 0;
1334 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1335 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1337 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && strlen(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1338 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1342 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1343 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1345 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && strlen(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1346 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1347 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1348 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1350 /* End Channel Specific Login Overrides */
1351 /* Read command line options */
1353 options = strchr(opt_user, '|');
1358 context = strchr(options, '@');
1364 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1371 option = (char)options[0];
1373 play_announcement = 0;
1375 badoption[0] = option;
1376 badoption[1] = '\0';
1377 tmpoptions=badoption;
1378 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1384 /* End command line options */
1386 if (chan->_state != AST_STATE_UP)
1387 res = ast_answer(chan);
1389 if( opt_user && !ast_strlen_zero(opt_user))
1390 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1392 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1394 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1396 /* Check for password */
1397 ast_mutex_lock(&agentlock);
1400 if (!strcmp(p->agent, user) && !p->pending)
1401 strncpy(xpass, p->password, sizeof(xpass) - 1);
1404 ast_mutex_unlock(&agentlock);
1406 if (!ast_strlen_zero(xpass))
1407 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1411 errmsg = "agent-incorrect";
1414 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1417 /* Check again for accuracy */
1418 ast_mutex_lock(&agentlock);
1421 ast_mutex_lock(&p->lock);
1422 if (!strcmp(p->agent, user) &&
1423 !strcmp(p->password, pass) && !p->pending) {
1424 login_state = 1; /* Successful Login */
1425 /* Set Channel Specific Agent Overides */
1426 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1427 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1429 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1433 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1434 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1436 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1437 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1438 if (p->autologoff < 0)
1440 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1441 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1443 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1444 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1445 if (p->wrapuptime < 0)
1447 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1448 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1450 /* End Channel Specific Agent Overides */
1452 char last_loginchan[80] = "";
1454 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1457 char tmpchan[AST_MAX_BUF] = "";
1459 /* Retrieve login chan */
1462 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1465 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1466 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1470 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1474 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, context && !ast_strlen_zero(context) ? context : "default", p->agent);
1475 res = ast_streamfile(chan, "invalid", chan->language);
1477 res = ast_waitstream(chan, AST_DIGIT_ANY);
1490 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1491 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1493 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1494 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1496 if (ast_strlen_zero(p->loginchan)) {
1498 filename = "agent-loggedoff";
1500 p->acknowledged = 0;
1501 /* store/clear the global variable that stores agentid based on the callerid */
1502 if (chan->cid.cid_num) {
1503 char agentvar[AST_MAX_BUF];
1504 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1505 if (ast_strlen_zero(p->loginchan))
1506 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1508 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1510 if(update_cdr && chan->cdr)
1511 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1515 p->loginchan[0] = '\0';
1516 p->acknowledged = 0;
1518 ast_mutex_unlock(&p->lock);
1519 ast_mutex_unlock(&agentlock);
1520 if( !res && play_announcement==1 )
1521 res = ast_streamfile(chan, filename, chan->language);
1523 ast_waitstream(chan, "");
1524 ast_mutex_lock(&agentlock);
1525 ast_mutex_lock(&p->lock);
1527 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1529 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1532 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1534 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1536 /* Check once more just in case */
1539 if (callbackmode && !res) {
1540 /* Just say goodbye and be done with it */
1541 if (!ast_strlen_zero(p->loginchan)) {
1542 if (p->loginstart == 0)
1543 time(&p->loginstart);
1544 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1548 p->agent, p->loginchan, chan->uniqueid);
1549 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1550 if (option_verbose > 2)
1551 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1552 ast_device_state_changed("Agent/%s", p->agent);
1554 logintime = time(NULL) - p->loginstart;
1556 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1559 "Logintime: %ld\r\n"
1561 p->agent, last_loginchan, logintime, chan->uniqueid);
1562 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1563 if (option_verbose > 2)
1564 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged out\n", p->agent);
1565 ast_device_state_changed("Agent/%s", p->agent);
1567 ast_mutex_unlock(&agentlock);
1569 res = ast_safe_sleep(chan, 500);
1570 ast_mutex_unlock(&p->lock);
1572 #ifdef HONOR_MUSIC_CLASS
1573 /* check if the moh class was changed with setmusiconhold */
1574 if (*(chan->musicclass))
1575 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1577 ast_moh_start(chan, p->moh);
1578 if (p->loginstart == 0)
1579 time(&p->loginstart);
1580 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1584 p->agent, chan->name, chan->uniqueid);
1585 if (update_cdr && chan->cdr)
1586 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1587 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1588 if (option_verbose > 2)
1589 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1590 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1591 /* Login this channel and wait for it to
1597 check_availability(p, 0);
1598 ast_mutex_unlock(&p->lock);
1599 ast_mutex_unlock(&agentlock);
1600 ast_device_state_changed("Agent/%s", p->agent);
1602 ast_mutex_lock(&p->lock);
1603 if (p->chan != chan)
1605 ast_mutex_unlock(&p->lock);
1606 /* Yield here so other interested threads can kick in. */
1611 ast_mutex_lock(&agentlock);
1612 ast_mutex_lock(&p->lock);
1613 if (p->lastdisc.tv_sec) {
1614 gettimeofday(&tv, NULL);
1615 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1616 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1617 ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1618 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1622 check_availability(p, 0);
1625 ast_mutex_unlock(&p->lock);
1626 ast_mutex_unlock(&agentlock);
1627 /* Synchronize channel ownership between call to agent and itself. */
1628 ast_mutex_lock( &p->app_lock );
1629 ast_mutex_lock(&p->lock);
1630 p->owning_app = pthread_self();
1631 ast_mutex_unlock(&p->lock);
1633 res = agent_ack_sleep(p);
1635 res = ast_safe_sleep_conditional( chan, 1000,
1636 agent_cont_sleep, p );
1637 ast_mutex_unlock( &p->app_lock );
1638 if ((p->ackcall > 1) && (res == 1)) {
1639 ast_mutex_lock(&agentlock);
1640 ast_mutex_lock(&p->lock);
1641 check_availability(p, 0);
1642 ast_mutex_unlock(&p->lock);
1643 ast_mutex_unlock(&agentlock);
1648 ast_mutex_lock(&p->lock);
1649 if (res && p->owner)
1650 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1651 /* Log us off if appropriate */
1652 if (p->chan == chan)
1654 p->acknowledged = 0;
1655 logintime = time(NULL) - p->loginstart;
1657 ast_mutex_unlock(&p->lock);
1658 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1660 "Logintime: %ld\r\n"
1662 p->agent, logintime, chan->uniqueid);
1663 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1664 if (option_verbose > 2)
1665 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1666 /* If there is no owner, go ahead and kill it now */
1667 ast_device_state_changed("Agent/%s", p->agent);
1668 if (p->dead && !p->owner) {
1669 ast_mutex_destroy(&p->lock);
1670 ast_mutex_destroy(&p->app_lock);
1675 ast_mutex_unlock(&p->lock);
1680 ast_mutex_unlock(&p->lock);
1681 errmsg = "agent-alreadyon";
1686 ast_mutex_unlock(&p->lock);
1690 ast_mutex_unlock(&agentlock);
1692 if (!res && (max_login_tries==0 || tries < max_login_tries))
1693 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1696 LOCAL_USER_REMOVE(u);
1698 res = ast_safe_sleep(chan, 500);
1700 /* AgentLogin() exit */
1701 if (!callbackmode) {
1704 /* AgentCallbackLogin() exit*/
1707 if (login_state > 0) {
1708 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1709 if (login_state==1) {
1710 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1711 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1714 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1718 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1720 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1722 /* Do we need to play agent-goodbye now that we will be hanging up? */
1723 if (play_announcement==1) {
1725 res = ast_safe_sleep(chan, 1000);
1726 res = ast_streamfile(chan, agent_goodbye, chan->language);
1728 res = ast_waitstream(chan, "");
1730 res = ast_safe_sleep(chan, 1000);
1733 /* We should never get here if next priority exists when in callbackmode */
1737 static int login_exec(struct ast_channel *chan, void *data)
1739 return __login_exec(chan, data, 0);
1742 static int callback_exec(struct ast_channel *chan, void *data)
1744 return __login_exec(chan, data, 1);
1747 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1749 int exitifnoagentid = 0;
1752 char agent[AST_MAX_AGENT], *tmp;
1754 if (strchr(data, 'd'))
1755 exitifnoagentid = 1;
1756 if (strchr(data, 'n'))
1759 if (chan->cid.cid_num) {
1760 char agentvar[AST_MAX_BUF];
1761 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1762 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1763 struct agent_pvt *p = agents;
1764 strncpy(agent, tmp, sizeof(agent) - 1);
1765 ast_mutex_lock(&agentlock);
1767 if (!strcasecmp(p->agent, tmp)) {
1768 __agent_start_monitoring(chan, p, 1);
1773 ast_mutex_unlock(&agentlock);
1778 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);
1783 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");
1785 /* check if there is n + 101 priority */
1787 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1788 chan->priority+=100;
1789 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1791 else if (exitifnoagentid)
1797 /*--- sip_devicestate: Part of PBX channel interface ---*/
1798 static int agent_devicestate(void *data)
1800 struct agent_pvt *p;
1802 unsigned int groupmatch;
1804 int res = AST_DEVICE_INVALID;
1807 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1808 groupmatch = (1 << groupmatch);
1809 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1810 groupmatch = (1 << groupmatch);
1816 /* Check actual logged in agents first */
1817 ast_mutex_lock(&agentlock);
1820 ast_mutex_lock(&p->lock);
1821 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1823 if (res != AST_DEVICE_INUSE)
1824 res = AST_DEVICE_BUSY;
1826 if (res == AST_DEVICE_BUSY)
1827 res = AST_DEVICE_INUSE;
1828 if (p->chan || !ast_strlen_zero(p->loginchan)) {
1829 if (res == AST_DEVICE_INVALID)
1830 res = AST_DEVICE_UNKNOWN;
1831 } else if (res == AST_DEVICE_INVALID)
1832 res = AST_DEVICE_UNAVAILABLE;
1834 if (!strcmp(data, p->agent)) {
1835 ast_mutex_unlock(&p->lock);
1839 ast_mutex_unlock(&p->lock);
1842 ast_mutex_unlock(&agentlock);
1848 /* Make sure we can register our sip channel type */
1849 if (ast_channel_register_ex(type, tdesc, capability, agent_request, agent_devicestate)) {
1850 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1853 ast_register_application(app, login_exec, synopsis, descrip);
1854 ast_register_application(app2, callback_exec, synopsis2, descrip2);
1855 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1856 ast_manager_register2("Agents", 0, action_agents, "Agents", mandescr_agents);
1857 ast_cli_register(&cli_show_agents);
1858 /* Read in the config */
1859 read_agent_config();
1865 read_agent_config();
1871 struct agent_pvt *p;
1872 /* First, take us out of the channel loop */
1873 ast_cli_unregister(&cli_show_agents);
1874 ast_unregister_application(app);
1875 ast_unregister_application(app2);
1876 ast_unregister_application(app3);
1877 ast_channel_unregister(type);
1878 ast_manager_unregister("Agents");
1879 if (!ast_mutex_lock(&agentlock)) {
1880 /* Hangup all interfaces if they have an owner */
1884 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1888 ast_mutex_unlock(&agentlock);
1890 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1899 ast_mutex_lock(&usecnt_lock);
1901 ast_mutex_unlock(&usecnt_lock);
1907 return ASTERISK_GPL_KEY;