2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Agents
6 * Copyright (C) 1999 - 2005, 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 <asterisk/astdb.h>
39 #include <sys/socket.h>
45 #include <arpa/inet.h>
46 #include <sys/signal.h>
48 static char *desc = "Agent Proxy Channel";
49 static char *channeltype = "Agent";
50 static char *tdesc = "Call Agent Proxy Channel";
51 static char *config = "agents.conf";
53 static char *app = "AgentLogin";
54 static char *app2 = "AgentCallbackLogin";
55 static char *app3 = "AgentMonitorOutgoing";
57 static char *synopsis = "Call agent login";
58 static char *synopsis2 = "Call agent callback login";
59 static char *synopsis3 = "Record agent's outgoing call";
61 static char *descrip =
62 " AgentLogin([AgentNo][|options]):\n"
63 "Asks the agent to login to the system. Always returns -1. While\n"
64 "logged in, the agent can receive calls and will hear a 'beep'\n"
65 "when a new call comes in. The agent can dump the call by pressing\n"
67 "The option string may contain zero or more of the following characters:\n"
68 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
70 static char *descrip2 =
71 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
72 "Asks the agent to login to the system with callback.\n"
73 "The agent's callback extension is called (optionally with the specified\n"
75 "The option string may contain zero or more of the following characters:\n"
76 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
80 static char *descrip3 =
81 " AgentMonitorOutgoing([options]):\n"
82 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
83 "comparision of the callerid of the current interface and the global variable \n"
84 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
85 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
86 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
88 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
89 "the agentid are not specified it'll look for n+101 priority.\n"
91 " 'd' - make the app return -1 if there is an error condition and there is\n"
92 " no extension n+101\n"
93 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
94 " 'n' - don't generate the warnings when there is no callerid or the\n"
95 " agentid is not known.\n"
96 " It's handy if you want to have one context for agent and non-agent calls.\n";
98 static char mandescr_agents[] =
99 "Description: Will list info about all possible agents.\n"
102 static char moh[80] = "default";
104 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
105 #define AST_MAX_BUF 256
106 #define AST_MAX_FILENAME_LEN 256
108 /* Persistent Agents astdb family */
109 static const char *pa_family = "/Agents";
110 /* The maximum lengh of each persistent member agent database entry */
111 #define PA_MAX_LEN 2048
112 /* queues.conf [general] option */
113 static int persistent_agents = 0;
114 static void dump_agents(void);
116 static int capability = -1;
118 static ast_group_t group;
119 static int autologoff;
120 static int wrapuptime;
123 static int maxlogintries = 3;
124 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
126 static int usecnt =0;
127 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
129 /* Protect the interface list (of pvt's) */
130 AST_MUTEX_DEFINE_STATIC(agentlock);
132 static int recordagentcalls = 0;
133 static char recordformat[AST_MAX_BUF] = "";
134 static char recordformatext[AST_MAX_BUF] = "";
135 static int createlink = 0;
136 static char urlprefix[AST_MAX_BUF] = "";
137 static char savecallsin[AST_MAX_BUF] = "";
138 static int updatecdr = 0;
139 static char beep[AST_MAX_BUF] = "beep";
141 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
143 static struct agent_pvt {
144 ast_mutex_t lock; /* Channel private lock */
145 int dead; /* Poised for destruction? */
146 int pending; /* Not a real agent -- just pending a match */
147 int abouttograb; /* About to grab */
148 int autologoff; /* Auto timeout time */
149 int ackcall; /* ackcall */
150 time_t loginstart; /* When agent first logged in (0 when logged off) */
151 time_t start; /* When call started */
152 struct timeval lastdisc; /* When last disconnected */
153 int wrapuptime; /* Wrapup time in ms */
154 ast_group_t group; /* Group memberships */
155 int acknowledged; /* Acknowledged */
156 char moh[80]; /* Which music on hold */
157 char agent[AST_MAX_AGENT]; /* Agent ID */
158 char password[AST_MAX_AGENT]; /* Password for Agent login */
159 char name[AST_MAX_AGENT];
160 ast_mutex_t app_lock; /* Synchronization between owning applications */
161 volatile pthread_t owning_app; /* Owning application thread id */
162 volatile int app_sleep_cond; /* Sleep condition for the login app */
163 struct ast_channel *owner; /* Agent */
165 struct ast_channel *chan; /* Channel we use */
166 struct agent_pvt *next; /* Agent */
169 #define CHECK_FORMATS(ast, p) do { \
171 if (ast->nativeformats != p->chan->nativeformats) { \
172 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
173 /* Native formats changed, reset things */ \
174 ast->nativeformats = p->chan->nativeformats; \
175 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
176 ast_set_read_format(ast, ast->readformat); \
177 ast_set_write_format(ast, ast->writeformat); \
179 if (p->chan->readformat != ast->pvt->rawreadformat) \
180 ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
181 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
182 ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
186 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
187 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
188 totally impractical combinations XXX */
190 #define CLEANUP(ast, p) do { \
193 for (x=0;x<AST_MAX_FDS;x++) {\
194 if (x != AST_MAX_FDS - 2) \
195 ast->fds[x] = p->chan->fds[x]; \
197 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
203 static void agent_unlink(struct agent_pvt *agent)
205 struct agent_pvt *p, *prev;
211 prev->next = agent->next;
213 agents = agent->next;
221 static struct agent_pvt *add_agent(char *agent, int pending)
223 char tmp[AST_MAX_BUF] = "";
224 char *password=NULL, *name=NULL;
225 struct agent_pvt *p, *prev;
227 strncpy(tmp, agent, sizeof(tmp) - 1);
228 if ((password = strchr(tmp, ','))) {
231 while (*password < 33) password++;
233 if (password && (name = strchr(password, ','))) {
236 while (*name < 33) name++;
241 if (!pending && !strcmp(p->agent, tmp))
247 p = malloc(sizeof(struct agent_pvt));
249 memset(p, 0, sizeof(struct agent_pvt));
250 strncpy(p->agent, tmp, sizeof(p->agent) -1);
251 ast_mutex_init(&p->lock);
252 ast_mutex_init(&p->app_lock);
253 p->owning_app = (pthread_t) -1;
254 p->app_sleep_cond = 1;
256 p->pending = pending;
267 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
268 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
269 strncpy(p->moh, moh, sizeof(p->moh) - 1);
270 p->ackcall = ackcall;
271 p->autologoff = autologoff;
272 p->wrapuptime = wrapuptime;
280 static int agent_cleanup(struct agent_pvt *p)
282 struct ast_channel *chan = p->owner;
284 chan->pvt->pvt = NULL;
285 p->app_sleep_cond = 1;
286 /* Release ownership of the agent to other threads (presumably running the login app). */
287 ast_mutex_unlock(&p->app_lock);
289 ast_channel_free(chan);
291 ast_mutex_destroy(&p->lock);
292 ast_mutex_destroy(&p->app_lock);
298 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
300 static int agent_answer(struct ast_channel *ast)
302 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
306 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
308 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
309 char filename[AST_MAX_BUF];
314 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
315 /* substitute . for - */
316 if ((pointer = strchr(filename, '.')))
318 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
319 ast_monitor_start(ast, recordformat, tmp, needlock);
320 ast_monitor_setjoinfiles(ast, 1);
321 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
323 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
326 ast->cdr = ast_cdr_alloc();
327 ast_cdr_setuserfield(ast, tmp2);
330 ast_log(LOG_ERROR, "Recording already started on that call.\n");
334 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
336 return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
339 static struct ast_frame *agent_read(struct ast_channel *ast)
341 struct agent_pvt *p = ast->pvt->pvt;
342 struct ast_frame *f = NULL;
343 static struct ast_frame null_frame = { AST_FRAME_NULL, };
344 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
345 ast_mutex_lock(&p->lock);
346 CHECK_FORMATS(ast, p);
348 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
349 if (ast->fdno == AST_MAX_FDS - 3)
350 p->chan->fdno = AST_MAX_FDS - 2;
352 p->chan->fdno = ast->fdno;
353 f = ast_read(p->chan);
357 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
359 /* Note that we don't hangup if it's not a callback because Asterisk will do it
360 for us when the PBX instance that called login finishes */
361 if (!ast_strlen_zero(p->loginchan)) {
362 p->chan->_bridge = NULL;
364 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
367 gettimeofday(&p->lastdisc, NULL);
368 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
369 if (p->lastdisc.tv_usec > 1000000) {
370 p->lastdisc.tv_usec -= 1000000;
371 p->lastdisc.tv_sec++;
373 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
380 if (p->chan && f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
382 ast_log(LOG_DEBUG, "Got answer on %s\n", p->chan->name);
384 if (option_verbose > 2)
385 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
386 /* Don't pass answer along */
395 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
396 if (!p->acknowledged) {
397 if (option_verbose > 2)
398 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
404 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
405 /* * terminates call */
409 if (f && (f->frametype == AST_FRAME_VOICE) && !p->acknowledged) {
410 /* Don't pass along agent audio until call is acknowledged */
415 if (p->chan && !p->chan->_bridge) {
416 if (strcasecmp(p->chan->type, "Local")) {
417 p->chan->_bridge = ast;
419 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
422 ast_mutex_unlock(&p->lock);
423 if (recordagentcalls && f == &answer_frame)
424 agent_start_monitoring(ast,0);
428 static int agent_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen)
430 struct agent_pvt *p = ast->pvt->pvt;
432 ast_mutex_lock(&p->lock);
434 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
435 ast_mutex_unlock(&p->lock);
439 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
441 struct agent_pvt *p = ast->pvt->pvt;
443 CHECK_FORMATS(ast, p);
444 ast_mutex_lock(&p->lock);
446 if ((f->frametype != AST_FRAME_VOICE) ||
447 (f->subclass == p->chan->writeformat)) {
448 res = ast_write(p->chan, f);
450 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
456 ast_mutex_unlock(&p->lock);
460 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
462 struct agent_pvt *p = newchan->pvt->pvt;
463 ast_mutex_lock(&p->lock);
464 if (p->owner != oldchan) {
465 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
466 ast_mutex_unlock(&p->lock);
470 ast_mutex_unlock(&p->lock);
474 static int agent_indicate(struct ast_channel *ast, int condition)
476 struct agent_pvt *p = ast->pvt->pvt;
478 ast_mutex_lock(&p->lock);
480 res = ast_indicate(p->chan, condition);
483 ast_mutex_unlock(&p->lock);
487 static int agent_digit(struct ast_channel *ast, char digit)
489 struct agent_pvt *p = ast->pvt->pvt;
491 ast_mutex_lock(&p->lock);
493 res = p->chan->pvt->send_digit(p->chan, digit);
496 ast_mutex_unlock(&p->lock);
500 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
502 struct agent_pvt *p = ast->pvt->pvt;
505 ast_mutex_lock(&p->lock);
509 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
510 newstate = AST_STATE_DIALING;
513 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
516 ast_mutex_unlock(&p->lock);
518 ast_setstate(ast, newstate);
520 } else if (!ast_strlen_zero(p->loginchan)) {
522 /* Call on this agent */
523 if (option_verbose > 2)
524 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
525 if (p->chan->cid.cid_num)
526 free(p->chan->cid.cid_num);
527 if (ast->cid.cid_num)
528 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
530 p->chan->cid.cid_num = NULL;
531 if (p->chan->cid.cid_name)
532 free(p->chan->cid.cid_name);
533 if (ast->cid.cid_name)
534 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
536 p->chan->cid.cid_name = NULL;
537 ast_channel_inherit_variables(ast, p->chan);
538 res = ast_call(p->chan, p->loginchan, 0);
540 ast_mutex_unlock(&p->lock);
543 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
544 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
545 res = ast_streamfile(p->chan, beep, p->chan->language);
546 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
548 res = ast_waitstream(p->chan, "");
549 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
552 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
553 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
555 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
562 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
563 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
565 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
569 /* Call is immediately up, or might need ack */
571 newstate = AST_STATE_RINGING;
573 newstate = AST_STATE_UP;
574 if (recordagentcalls)
575 agent_start_monitoring(ast,0);
581 ast_mutex_unlock(&p->lock);
583 ast_setstate(ast, newstate);
587 static int agent_hangup(struct ast_channel *ast)
589 struct agent_pvt *p = ast->pvt->pvt;
591 ast_mutex_lock(&p->lock);
593 ast->pvt->pvt = NULL;
594 p->app_sleep_cond = 1;
597 /* if they really are hung up then set start to 0 so the test
598 * later if we're called on an already downed channel
599 * doesn't cause an agent to be logged out like when
600 * agent_request() is followed immediately by agent_hangup()
601 * as in apps/app_chanisavail.c:chanavail_exec()
604 ast_mutex_lock(&usecnt_lock);
606 ast_mutex_unlock(&usecnt_lock);
608 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
609 if (p->start && (ast->_state != AST_STATE_UP)) {
610 howlong = time(NULL) - p->start;
612 } else if (ast->_state == AST_STATE_RESERVED) {
617 /* If they're dead, go ahead and hang up on the agent now */
618 if (!ast_strlen_zero(p->loginchan)) {
619 /* Store last disconnect time */
621 gettimeofday(&p->lastdisc, NULL);
622 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
623 if (p->lastdisc.tv_usec >= 1000000) {
624 p->lastdisc.tv_usec -= 1000000;
625 p->lastdisc.tv_sec++;
627 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
629 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
631 /* Recognize the hangup and pass it along immediately */
635 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
636 if (howlong && p->autologoff && (howlong > p->autologoff)) {
637 char agent[AST_MAX_AGENT] = "";
638 long logintime = time(NULL) - p->loginstart;
640 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
641 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
645 "Reason: Autologoff\r\n"
647 p->agent, p->loginchan, logintime, ast->uniqueid);
648 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
649 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
650 p->loginchan[0] = '\0';
651 ast_device_state_changed("Agent/%s", p->agent);
653 } else if (p->dead) {
654 ast_mutex_lock(&p->chan->lock);
655 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
656 ast_mutex_unlock(&p->chan->lock);
658 ast_mutex_lock(&p->chan->lock);
659 ast_moh_start(p->chan, p->moh);
660 ast_mutex_unlock(&p->chan->lock);
664 ast_mutex_unlock(&p->lock);
665 /* Release ownership of the agent to other threads (presumably running the login app). */
666 ast_mutex_unlock(&p->app_lock);
667 } else if (p->dead) {
668 /* Go ahead and lose it */
669 ast_mutex_unlock(&p->lock);
670 /* Release ownership of the agent to other threads (presumably running the login app). */
671 ast_mutex_unlock(&p->app_lock);
673 ast_mutex_unlock(&p->lock);
674 /* Release ownership of the agent to other threads (presumably running the login app). */
675 ast_mutex_unlock(&p->app_lock);
678 ast_mutex_unlock(&p->lock);
681 ast_mutex_lock(&agentlock);
683 ast_mutex_unlock(&agentlock);
685 if (p->abouttograb) {
686 /* Let the "about to grab" thread know this isn't valid anymore, and let it
689 } else if (p->dead) {
690 ast_mutex_destroy(&p->lock);
691 ast_mutex_destroy(&p->app_lock);
695 /* Not dead -- check availability now */
696 ast_mutex_lock(&p->lock);
697 /* Store last disconnect time */
698 gettimeofday(&p->lastdisc, NULL);
699 ast_mutex_unlock(&p->lock);
701 /* Release ownership of the agent to other threads (presumably running the login app). */
702 ast_mutex_unlock(&p->app_lock);
707 static int agent_cont_sleep( void *data )
713 p = (struct agent_pvt *)data;
715 ast_mutex_lock(&p->lock);
716 res = p->app_sleep_cond;
717 if (p->lastdisc.tv_sec) {
718 gettimeofday(&tv, NULL);
719 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
720 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
723 ast_mutex_unlock(&p->lock);
726 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
731 static int agent_ack_sleep( void *data )
738 /* Wait a second and look for something */
740 p = (struct agent_pvt *)data;
743 to = ast_waitfor(p->chan, to);
752 f = ast_read(p->chan);
757 if (f->frametype == AST_FRAME_DTMF)
762 ast_mutex_lock(&p->lock);
763 if (!p->app_sleep_cond) {
764 ast_mutex_unlock(&p->lock);
767 } else if (res == '#') {
768 ast_mutex_unlock(&p->lock);
772 ast_mutex_unlock(&p->lock);
780 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
783 struct ast_channel *ret=NULL;
786 p = bridge->pvt->pvt;
788 ret = bridge->_bridge;
789 else if (chan == bridge->_bridge)
792 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
796 /*--- agent_new: Create new agent channel ---*/
797 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
799 struct ast_channel *tmp;
800 struct ast_frame null_frame = { AST_FRAME_NULL };
803 ast_log(LOG_WARNING, "No channel? :(\n");
807 tmp = ast_channel_alloc(0);
810 tmp->nativeformats = p->chan->nativeformats;
811 tmp->writeformat = p->chan->writeformat;
812 tmp->pvt->rawwriteformat = p->chan->writeformat;
813 tmp->readformat = p->chan->readformat;
814 tmp->pvt->rawreadformat = p->chan->readformat;
815 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
816 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
817 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
819 tmp->nativeformats = AST_FORMAT_SLINEAR;
820 tmp->writeformat = AST_FORMAT_SLINEAR;
821 tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
822 tmp->readformat = AST_FORMAT_SLINEAR;
823 tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
826 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
828 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
829 tmp->type = channeltype;
830 /* Safe, agentlock already held */
831 ast_setstate(tmp, state);
833 tmp->pvt->send_digit = agent_digit;
834 tmp->pvt->call = agent_call;
835 tmp->pvt->hangup = agent_hangup;
836 tmp->pvt->answer = agent_answer;
837 tmp->pvt->read = agent_read;
838 tmp->pvt->write = agent_write;
839 tmp->pvt->send_html = agent_sendhtml;
840 tmp->pvt->exception = agent_read;
841 tmp->pvt->indicate = agent_indicate;
842 tmp->pvt->fixup = agent_fixup;
843 tmp->pvt->bridged_channel = agent_bridgedchannel;
845 ast_mutex_lock(&usecnt_lock);
847 ast_mutex_unlock(&usecnt_lock);
848 ast_update_use_count();
850 /* Wake up and wait for other applications (by definition the login app)
851 * to release this channel). Takes ownership of the agent channel
852 * to this thread only.
853 * For signalling the other thread, ast_queue_frame is used until we
854 * can safely use signals for this purpose. The pselect() needs to be
855 * implemented in the kernel for this.
857 p->app_sleep_cond = 0;
858 if( ast_mutex_trylock(&p->app_lock) )
861 ast_queue_frame(p->chan, &null_frame);
862 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
863 ast_mutex_lock(&p->app_lock);
864 ast_mutex_lock(&p->lock);
868 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
870 tmp->pvt->pvt = NULL;
871 p->app_sleep_cond = 1;
872 ast_channel_free( tmp );
873 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
874 ast_mutex_unlock(&p->app_lock);
878 p->owning_app = pthread_self();
879 /* After the above step, there should not be any blockers. */
881 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
882 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
885 ast_moh_stop(p->chan);
888 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
893 /*--- read_agent_config: Read configuration data (agents.conf) ---*/
894 static int read_agent_config(void)
896 struct ast_config *cfg;
897 struct ast_variable *v;
898 struct agent_pvt *p, *pl, *pn;
905 cfg = ast_config_load(config);
907 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
910 ast_mutex_lock(&agentlock);
916 strncpy(moh, "default", sizeof(moh) - 1);
917 /* set the default recording values */
918 recordagentcalls = 0;
920 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
921 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
923 savecallsin[0] = '\0';
925 /* Read in [general] section for persistance */
926 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
927 persistent_agents = ast_true(general_val);
929 /* Read in the [agents] section */
930 v = ast_variable_browse(cfg, "agents");
932 /* Create the interface list */
933 if (!strcasecmp(v->name, "agent")) {
934 add_agent(v->value, 0);
935 } else if (!strcasecmp(v->name, "group")) {
936 group = ast_get_group(v->value);
937 } else if (!strcasecmp(v->name, "autologoff")) {
938 autologoff = atoi(v->value);
941 } else if (!strcasecmp(v->name, "ackcall")) {
942 if (!strcasecmp(v->value, "always"))
944 else if (ast_true(v->value))
948 } else if (!strcasecmp(v->name, "wrapuptime")) {
949 wrapuptime = atoi(v->value);
952 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
953 maxlogintries = atoi(v->value);
954 if (maxlogintries < 0)
956 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
957 strcpy(agentgoodbye,v->value);
958 } else if (!strcasecmp(v->name, "musiconhold")) {
959 strncpy(moh, v->value, sizeof(moh) - 1);
960 } else if (!strcasecmp(v->name, "updatecdr")) {
961 if (ast_true(v->value))
965 } else if (!strcasecmp(v->name, "recordagentcalls")) {
966 recordagentcalls = ast_true(v->value);
967 } else if (!strcasecmp(v->name, "createlink")) {
968 createlink = ast_true(v->value);
969 } else if (!strcasecmp(v->name, "recordformat")) {
970 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
971 if (!strcasecmp(v->value, "wav49"))
972 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
974 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
975 } else if (!strcasecmp(v->name, "urlprefix")) {
976 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
977 if (urlprefix[strlen(urlprefix) - 1] != '/')
978 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
979 } else if (!strcasecmp(v->name, "savecallsin")) {
980 if (v->value[0] == '/')
981 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
983 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
984 if (savecallsin[strlen(savecallsin) - 1] != '/')
985 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
986 } else if (!strcasecmp(v->name, "custom_beep")) {
987 strncpy(beep, v->value, sizeof(beep) - 1);
1001 /* Destroy if appropriate */
1004 ast_mutex_destroy(&p->lock);
1005 ast_mutex_destroy(&p->app_lock);
1008 /* Cause them to hang up */
1009 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1016 ast_mutex_unlock(&agentlock);
1017 ast_config_destroy(cfg);
1021 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1023 struct ast_channel *chan=NULL, *parent=NULL;
1024 struct agent_pvt *p;
1028 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1030 ast_mutex_lock(&agentlock);
1033 if (p == newlyavailable) {
1037 ast_mutex_lock(&p->lock);
1038 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1040 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1041 /* We found a pending call, time to merge */
1042 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1045 ast_mutex_unlock(&p->lock);
1048 ast_mutex_unlock(&p->lock);
1052 ast_mutex_unlock(&agentlock);
1053 if (parent && chan) {
1054 if (newlyavailable->ackcall > 1) {
1055 /* Don't do beep here */
1058 if (option_debug > 2)
1059 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1060 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1061 if (option_debug > 2)
1062 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1064 res = ast_waitstream(newlyavailable->chan, "");
1065 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1069 /* Note -- parent may have disappeared */
1070 if (p->abouttograb) {
1071 newlyavailable->acknowledged = 1;
1072 /* Safe -- agent lock already held */
1073 ast_setstate(parent, AST_STATE_UP);
1074 ast_setstate(chan, AST_STATE_UP);
1075 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1076 /* Go ahead and mark the channel as a zombie so that masquerade will
1077 destroy it for us, and we need not call ast_hangup */
1078 ast_mutex_lock(&parent->lock);
1079 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1080 ast_channel_masquerade(parent, chan);
1081 ast_mutex_unlock(&parent->lock);
1085 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1086 agent_cleanup(newlyavailable);
1090 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1091 agent_cleanup(newlyavailable);
1097 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1099 struct agent_pvt *p;
1102 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1104 ast_mutex_lock(&agentlock);
1107 if (p == newlyavailable) {
1111 ast_mutex_lock(&p->lock);
1112 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1114 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1115 ast_mutex_unlock(&p->lock);
1118 ast_mutex_unlock(&p->lock);
1122 ast_mutex_unlock(&agentlock);
1124 ast_mutex_unlock(&newlyavailable->lock);
1125 if (option_debug > 2)
1126 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1127 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1128 if (option_debug > 2)
1129 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1131 res = ast_waitstream(newlyavailable->chan, "");
1133 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1135 ast_mutex_lock(&newlyavailable->lock);
1140 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1141 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1143 struct agent_pvt *p;
1144 struct ast_channel *chan = NULL;
1146 ast_group_t groupmatch;
1153 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1154 groupmatch = (1 << groupoff);
1155 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1156 groupmatch = (1 << groupoff);
1162 /* Check actual logged in agents first */
1163 ast_mutex_lock(&agentlock);
1166 ast_mutex_lock(&p->lock);
1167 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1168 ast_strlen_zero(p->loginchan)) {
1171 if (!p->lastdisc.tv_sec) {
1172 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1173 if (!p->owner && p->chan) {
1175 chan = agent_new(p, AST_STATE_DOWN);
1178 ast_mutex_unlock(&p->lock);
1183 ast_mutex_unlock(&p->lock);
1189 ast_mutex_lock(&p->lock);
1190 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1191 if (p->chan || !ast_strlen_zero(p->loginchan))
1193 gettimeofday(&tv, NULL);
1195 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1197 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1198 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1199 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1200 if (!p->owner && p->chan) {
1201 /* Could still get a fixed agent */
1202 chan = agent_new(p, AST_STATE_DOWN);
1203 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1204 /* Adjustable agent */
1205 p->chan = ast_request("Local", format, p->loginchan, cause);
1207 chan = agent_new(p, AST_STATE_DOWN);
1210 ast_mutex_unlock(&p->lock);
1215 ast_mutex_unlock(&p->lock);
1220 if (!chan && waitforagent) {
1221 /* No agent available -- but we're requesting to wait for one.
1222 Allocate a place holder */
1225 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1226 p = add_agent(data, 1);
1227 p->group = groupmatch;
1228 chan = agent_new(p, AST_STATE_DOWN);
1230 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1233 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1236 *cause = AST_CAUSE_BUSY;
1238 *cause = AST_CAUSE_UNREGISTERED;
1239 ast_mutex_unlock(&agentlock);
1243 static int powerof(unsigned int v)
1246 for (x=0;x<32;x++) {
1247 if (v & (1 << x)) return x;
1252 /*--- action_agents: Manager routine for listing channels */
1253 static int action_agents(struct mansession *s, struct message *m)
1255 struct agent_pvt *p;
1256 char *username = NULL;
1257 char *loginChan = NULL;
1258 char *talkingtoChan = NULL;
1259 char *status = NULL;
1261 ast_mutex_lock(&agentlock);
1264 ast_mutex_lock(&p->lock);
1267 AGENT_LOGGEDOFF - Agent isn't logged in
1268 AGENT_IDLE - Agent is logged in, and waiting for call
1269 AGENT_ONCALL - Agent is logged in, and on a call
1270 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1272 if(!ast_strlen_zero(p->name)) {
1278 /* Set a default status. It 'should' get changed. */
1279 status = "AGENT_UNKNOWN";
1282 loginChan = p->loginchan;
1283 if(p->owner && p->owner->_bridge) {
1284 talkingtoChan = p->chan->cid.cid_num;
1285 status = "AGENT_ONCALL";
1287 talkingtoChan = "n/a";
1288 status = "AGENT_IDLE";
1290 } else if(!ast_strlen_zero(p->loginchan)) {
1291 loginChan = p->loginchan;
1292 talkingtoChan = "n/a";
1293 status = "AGENT_IDLE";
1294 if(p->acknowledged) {
1295 sprintf(loginChan, " %s (Confirmed)", loginChan);
1299 talkingtoChan = "n/a";
1300 status = "AGENT_LOGGEDOFF";
1303 ast_cli(s->fd, "Event: Agents\r\n"
1307 "LoggedInChan: %s\r\n"
1308 "LoggedInTime: %ld\r\n"
1311 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1312 ast_mutex_unlock(&p->lock);
1315 ast_mutex_unlock(&agentlock);
1319 static int agent_logoff_cmd(int fd, int argc, char **argv)
1321 struct agent_pvt *p;
1322 char *agent = argv[2] + 6;
1325 if (argc < 3 || argc > 4)
1326 return RESULT_SHOWUSAGE;
1327 if (argc == 4 && strcasecmp(argv[3], "soft"))
1328 return RESULT_SHOWUSAGE;
1330 for (p=agents; p; p=p->next) {
1331 if (!strcasecmp(p->agent, agent)) {
1334 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1337 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1340 logintime = time(NULL) - p->loginstart;
1343 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1346 "Logintime: %ld\r\n",
1347 p->agent, p->loginchan, logintime);
1348 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1349 p->loginchan[0] = '\0';
1350 ast_cli(fd, "Logging out %s\n", agent);
1354 return RESULT_SUCCESS;
1357 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1359 struct agent_pvt *p;
1360 char name[AST_MAX_AGENT];
1364 for (p=agents; p; p=p->next) {
1365 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1366 if (!strncasecmp(word, name, strlen(word))) {
1367 if (++which > state) {
1368 return strdup(name);
1372 } else if (pos == 3 && state == 0) {
1373 return strdup("soft");
1378 /*--- agents_show: Show agents in cli ---*/
1379 static int agents_show(int fd, int argc, char **argv)
1381 struct agent_pvt *p;
1382 char username[AST_MAX_BUF];
1383 char location[AST_MAX_BUF] = "";
1384 char talkingto[AST_MAX_BUF] = "";
1385 char moh[AST_MAX_BUF];
1388 return RESULT_SHOWUSAGE;
1389 ast_mutex_lock(&agentlock);
1392 ast_mutex_lock(&p->lock);
1395 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1397 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1399 if (!ast_strlen_zero(p->name))
1400 snprintf(username, sizeof(username), "(%s) ", p->name);
1404 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1405 if (p->owner && ast_bridged_channel(p->owner)) {
1406 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1408 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1410 } else if (!ast_strlen_zero(p->loginchan)) {
1411 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1412 talkingto[0] = '\0';
1413 if (p->acknowledged)
1414 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1416 strncpy(location, "not logged in", sizeof(location) - 1);
1417 talkingto[0] = '\0';
1419 if (!ast_strlen_zero(p->moh))
1420 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1421 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1422 username, location, talkingto, moh);
1424 ast_mutex_unlock(&p->lock);
1427 ast_mutex_unlock(&agentlock);
1428 return RESULT_SUCCESS;
1431 static char show_agents_usage[] =
1432 "Usage: show agents\n"
1433 " Provides summary information on agents.\n";
1435 static char agent_logoff_usage[] =
1436 "Usage: agent logoff <channel> [soft]\n"
1437 " Sets an agent as no longer logged in.\n"
1438 " If 'soft' is specified, do not hangup existing calls.\n";
1440 static struct ast_cli_entry cli_show_agents = {
1441 { "show", "agents", NULL }, agents_show,
1442 "Show status of agents", show_agents_usage, NULL };
1444 static struct ast_cli_entry cli_agent_logoff = {
1445 { "agent", "logoff", NULL }, agent_logoff_cmd,
1446 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1448 STANDARD_LOCAL_USER;
1451 /*--- __login_exec: Log in agent application ---*/
1452 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1456 int max_login_tries = maxlogintries;
1457 struct agent_pvt *p;
1458 struct localuser *u;
1460 int login_state = 0;
1461 char user[AST_MAX_AGENT] = "";
1462 char pass[AST_MAX_AGENT];
1463 char agent[AST_MAX_AGENT] = "";
1464 char xpass[AST_MAX_AGENT] = "";
1467 char *opt_user = NULL;
1468 char *options = NULL;
1471 char *tmpoptions = NULL;
1472 char *context = NULL;
1474 int play_announcement = 1;
1475 char agent_goodbye[AST_MAX_FILENAME_LEN];
1476 int update_cdr = updatecdr;
1477 char *filename = "agent-loginok";
1479 strcpy(agent_goodbye, agentgoodbye);
1482 /* Parse the arguments XXX Check for failure XXX */
1483 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1485 /* Set Channel Specific Login Overrides */
1486 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1487 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1488 if (max_login_tries < 0)
1489 max_login_tries = 0;
1490 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1491 if (option_verbose > 2)
1492 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);
1494 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1495 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1499 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1500 if (option_verbose > 2)
1501 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1503 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1504 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1505 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1506 if (option_verbose > 2)
1507 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1509 /* End Channel Specific Login Overrides */
1510 /* Read command line options */
1512 options = strchr(opt_user, '|');
1517 context = strchr(options, '@');
1523 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1530 option = (char)options[0];
1531 if ((option >= 0) && (option <= '9'))
1537 play_announcement = 0;
1539 badoption[0] = option;
1540 badoption[1] = '\0';
1541 tmpoptions=badoption;
1542 if (option_verbose > 2)
1543 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1549 /* End command line options */
1551 if (chan->_state != AST_STATE_UP)
1552 res = ast_answer(chan);
1554 if( opt_user && !ast_strlen_zero(opt_user))
1555 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1557 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1559 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1561 /* Check for password */
1562 ast_mutex_lock(&agentlock);
1565 if (!strcmp(p->agent, user) && !p->pending)
1566 strncpy(xpass, p->password, sizeof(xpass) - 1);
1569 ast_mutex_unlock(&agentlock);
1571 if (!ast_strlen_zero(xpass))
1572 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1576 errmsg = "agent-incorrect";
1579 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1582 /* Check again for accuracy */
1583 ast_mutex_lock(&agentlock);
1586 ast_mutex_lock(&p->lock);
1587 if (!strcmp(p->agent, user) &&
1588 !strcmp(p->password, pass) && !p->pending) {
1589 login_state = 1; /* Successful Login */
1590 /* Set Channel Specific Agent Overides */
1591 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1592 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1594 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1598 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1599 if (option_verbose > 2)
1600 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1602 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1603 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1604 if (p->autologoff < 0)
1606 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1607 if (option_verbose > 2)
1608 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1610 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1611 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1612 if (p->wrapuptime < 0)
1614 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1615 if (option_verbose > 2)
1616 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1618 /* End Channel Specific Agent Overides */
1620 char last_loginchan[80] = "";
1622 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1625 char tmpchan[AST_MAX_BUF] = "";
1627 /* Retrieve login chan */
1630 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1633 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1634 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1638 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1642 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);
1643 res = ast_streamfile(chan, "invalid", chan->language);
1645 res = ast_waitstream(chan, AST_DIGIT_ANY);
1658 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1659 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1661 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1662 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1664 if (ast_strlen_zero(p->loginchan)) {
1666 filename = "agent-loggedoff";
1668 p->acknowledged = 0;
1669 /* store/clear the global variable that stores agentid based on the callerid */
1670 if (chan->cid.cid_num) {
1671 char agentvar[AST_MAX_BUF];
1672 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1673 if (ast_strlen_zero(p->loginchan))
1674 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1676 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1678 if(update_cdr && chan->cdr)
1679 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1683 p->loginchan[0] = '\0';
1684 p->acknowledged = 0;
1686 ast_mutex_unlock(&p->lock);
1687 ast_mutex_unlock(&agentlock);
1688 if( !res && play_announcement==1 )
1689 res = ast_streamfile(chan, filename, chan->language);
1691 ast_waitstream(chan, "");
1692 ast_mutex_lock(&agentlock);
1693 ast_mutex_lock(&p->lock);
1695 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1697 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1700 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1702 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1704 /* Check once more just in case */
1707 if (callbackmode && !res) {
1708 /* Just say goodbye and be done with it */
1709 if (!ast_strlen_zero(p->loginchan)) {
1710 if (p->loginstart == 0)
1711 time(&p->loginstart);
1712 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1716 p->agent, p->loginchan, chan->uniqueid);
1717 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1718 if (option_verbose > 1)
1719 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1720 ast_device_state_changed("Agent/%s", p->agent);
1722 logintime = time(NULL) - p->loginstart;
1724 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1727 "Logintime: %ld\r\n"
1729 p->agent, last_loginchan, logintime, chan->uniqueid);
1730 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1731 if (option_verbose > 1)
1732 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1733 ast_device_state_changed("Agent/%s", p->agent);
1735 ast_mutex_unlock(&agentlock);
1737 res = ast_safe_sleep(chan, 500);
1738 ast_mutex_unlock(&p->lock);
1739 if (persistent_agents)
1742 #ifdef HONOR_MUSIC_CLASS
1743 /* check if the moh class was changed with setmusiconhold */
1744 if (*(chan->musicclass))
1745 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1747 ast_moh_start(chan, p->moh);
1748 if (p->loginstart == 0)
1749 time(&p->loginstart);
1750 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1754 p->agent, chan->name, chan->uniqueid);
1755 if (update_cdr && chan->cdr)
1756 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1757 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1758 if (option_verbose > 1)
1759 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1760 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1761 /* Login this channel and wait for it to
1767 check_availability(p, 0);
1768 ast_mutex_unlock(&p->lock);
1769 ast_mutex_unlock(&agentlock);
1770 ast_device_state_changed("Agent/%s", p->agent);
1772 ast_mutex_lock(&p->lock);
1773 if (p->chan != chan)
1775 ast_mutex_unlock(&p->lock);
1776 /* Yield here so other interested threads can kick in. */
1781 ast_mutex_lock(&agentlock);
1782 ast_mutex_lock(&p->lock);
1783 if (p->lastdisc.tv_sec) {
1784 gettimeofday(&tv, NULL);
1785 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1786 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1788 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1789 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1793 check_availability(p, 0);
1796 ast_mutex_unlock(&p->lock);
1797 ast_mutex_unlock(&agentlock);
1798 /* Synchronize channel ownership between call to agent and itself. */
1799 ast_mutex_lock( &p->app_lock );
1800 ast_mutex_lock(&p->lock);
1801 p->owning_app = pthread_self();
1802 ast_mutex_unlock(&p->lock);
1804 res = agent_ack_sleep(p);
1806 res = ast_safe_sleep_conditional( chan, 1000,
1807 agent_cont_sleep, p );
1808 ast_mutex_unlock( &p->app_lock );
1809 if ((p->ackcall > 1) && (res == 1)) {
1810 ast_mutex_lock(&agentlock);
1811 ast_mutex_lock(&p->lock);
1812 check_availability(p, 0);
1813 ast_mutex_unlock(&p->lock);
1814 ast_mutex_unlock(&agentlock);
1819 ast_mutex_lock(&p->lock);
1820 if (res && p->owner)
1821 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1822 /* Log us off if appropriate */
1823 if (p->chan == chan)
1825 p->acknowledged = 0;
1826 logintime = time(NULL) - p->loginstart;
1828 ast_mutex_unlock(&p->lock);
1829 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1831 "Logintime: %ld\r\n"
1833 p->agent, logintime, chan->uniqueid);
1834 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1835 if (option_verbose > 1)
1836 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1837 /* If there is no owner, go ahead and kill it now */
1838 ast_device_state_changed("Agent/%s", p->agent);
1839 if (p->dead && !p->owner) {
1840 ast_mutex_destroy(&p->lock);
1841 ast_mutex_destroy(&p->app_lock);
1846 ast_mutex_unlock(&p->lock);
1851 ast_mutex_unlock(&p->lock);
1852 errmsg = "agent-alreadyon";
1857 ast_mutex_unlock(&p->lock);
1861 ast_mutex_unlock(&agentlock);
1863 if (!res && (max_login_tries==0 || tries < max_login_tries))
1864 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1867 LOCAL_USER_REMOVE(u);
1869 res = ast_safe_sleep(chan, 500);
1871 /* AgentLogin() exit */
1872 if (!callbackmode) {
1875 /* AgentCallbackLogin() exit*/
1878 if (login_state > 0) {
1879 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1880 if (login_state==1) {
1881 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1882 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1885 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1889 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1891 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1893 /* Do we need to play agent-goodbye now that we will be hanging up? */
1894 if (play_announcement==1) {
1896 res = ast_safe_sleep(chan, 1000);
1897 res = ast_streamfile(chan, agent_goodbye, chan->language);
1899 res = ast_waitstream(chan, "");
1901 res = ast_safe_sleep(chan, 1000);
1904 /* We should never get here if next priority exists when in callbackmode */
1908 static int login_exec(struct ast_channel *chan, void *data)
1910 return __login_exec(chan, data, 0);
1913 static int callback_exec(struct ast_channel *chan, void *data)
1915 return __login_exec(chan, data, 1);
1918 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1920 int exitifnoagentid = 0;
1922 int changeoutgoing = 0;
1924 char agent[AST_MAX_AGENT], *tmp;
1927 if (strchr(data, 'd'))
1928 exitifnoagentid = 1;
1929 if (strchr(data, 'n'))
1931 if (strchr(data, 'c'))
1934 if (chan->cid.cid_num) {
1935 char agentvar[AST_MAX_BUF];
1936 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1937 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1938 struct agent_pvt *p = agents;
1939 strncpy(agent, tmp, sizeof(agent) - 1);
1940 ast_mutex_lock(&agentlock);
1942 if (!strcasecmp(p->agent, tmp)) {
1943 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1944 __agent_start_monitoring(chan, p, 1);
1949 ast_mutex_unlock(&agentlock);
1954 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);
1959 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");
1961 /* check if there is n + 101 priority */
1963 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1964 chan->priority+=100;
1965 if (option_verbose > 2)
1966 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1968 else if (exitifnoagentid)
1974 /* Dump AgentCallbackLogin agents to the database for persistence
1975 * (basically copied from dump_queue_members() in apps/app_queue.c)
1978 static void dump_agents(void)
1980 struct agent_pvt *cur_agent = NULL;
1983 if (cur_agent->chan != NULL) {
1984 cur_agent = cur_agent->next;
1987 if (!ast_strlen_zero(cur_agent->loginchan)) {
1988 if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan)) {
1989 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
1992 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n",
1993 cur_agent->agent, cur_agent->loginchan);
1998 /* Delete - no agent or there is an error */
1999 ast_db_del(pa_family, cur_agent->agent);
2001 cur_agent = cur_agent->next;
2005 /* Reload the persistent agents from astdb */
2006 static void reload_agents(void)
2009 struct ast_db_entry *pa_db_tree = NULL;
2010 int pa_family_len = 0;
2011 struct agent_pvt *cur_agent = NULL;
2012 char agent_data[80];
2014 pa_db_tree = ast_db_gettree(pa_family, NULL);
2016 pa_family_len = strlen(pa_family);
2017 ast_mutex_lock(&agentlock);
2018 while (pa_db_tree) {
2019 pa_agent_num = pa_db_tree->key + pa_family_len + 2;
2022 ast_mutex_lock(&cur_agent->lock);
2024 if (strcmp(pa_agent_num, cur_agent->agent) == 0)
2027 ast_mutex_unlock(&cur_agent->lock);
2028 cur_agent = cur_agent->next;
2031 ast_db_del(pa_family, pa_agent_num);
2032 pa_db_tree = pa_db_tree->next;
2035 ast_mutex_unlock(&cur_agent->lock);
2036 if (!ast_db_get(pa_family, pa_agent_num, agent_data, 80)) {
2038 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n",
2039 cur_agent->agent, agent_data);
2041 strncpy(cur_agent->loginchan,agent_data,80);
2042 if (cur_agent->loginstart == 0)
2043 time(&cur_agent->loginstart);
2044 ast_device_state_changed("Agent/%s", cur_agent->agent);
2046 pa_db_tree = pa_db_tree->next;
2048 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2049 ast_mutex_unlock(&agentlock);
2051 ast_db_freetree(pa_db_tree);
2057 /*--- agent_devicestate: Part of PBX channel interface ---*/
2058 static int agent_devicestate(void *data)
2060 struct agent_pvt *p;
2062 ast_group_t groupmatch;
2065 int res = AST_DEVICE_INVALID;
2068 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2069 groupmatch = (1 << groupoff);
2070 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2071 groupmatch = (1 << groupoff);
2077 /* Check actual logged in agents first */
2078 ast_mutex_lock(&agentlock);
2081 ast_mutex_lock(&p->lock);
2082 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2084 if (res != AST_DEVICE_INUSE)
2085 res = AST_DEVICE_BUSY;
2087 if (res == AST_DEVICE_BUSY)
2088 res = AST_DEVICE_INUSE;
2089 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2090 if (res == AST_DEVICE_INVALID)
2091 res = AST_DEVICE_UNKNOWN;
2092 } else if (res == AST_DEVICE_INVALID)
2093 res = AST_DEVICE_UNAVAILABLE;
2095 if (!strcmp(data, p->agent)) {
2096 ast_mutex_unlock(&p->lock);
2100 ast_mutex_unlock(&p->lock);
2103 ast_mutex_unlock(&agentlock);
2107 /*--- load_module: Initialize channel module ---*/
2110 /* Make sure we can register our agent channel type */
2111 if (ast_channel_register_ex(channeltype, tdesc, capability, agent_request, agent_devicestate)) {
2112 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2115 /* Dialplan applications */
2116 ast_register_application(app, login_exec, synopsis, descrip);
2117 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2118 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2119 /* Manager command */
2120 ast_manager_register2("Agents", 0, action_agents, "Lists agents and their status", mandescr_agents);
2121 /* CLI Application */
2122 ast_cli_register(&cli_show_agents);
2123 ast_cli_register(&cli_agent_logoff);
2124 /* Read in the config */
2125 read_agent_config();
2126 if (persistent_agents)
2133 read_agent_config();
2134 if (persistent_agents)
2141 struct agent_pvt *p;
2142 /* First, take us out of the channel loop */
2143 /* Unregister CLI application */
2144 ast_cli_unregister(&cli_show_agents);
2145 ast_cli_unregister(&cli_agent_logoff);
2146 /* Unregister dialplan applications */
2147 ast_unregister_application(app);
2148 ast_unregister_application(app2);
2149 ast_unregister_application(app3);
2150 /* Unregister manager command */
2151 ast_manager_unregister("Agents");
2152 /* Unregister channel */
2153 ast_channel_unregister(channeltype);
2154 if (!ast_mutex_lock(&agentlock)) {
2155 /* Hangup all interfaces if they have an owner */
2159 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2163 ast_mutex_unlock(&agentlock);
2165 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2174 ast_mutex_lock(&usecnt_lock);
2176 ast_mutex_unlock(&usecnt_lock);
2182 return ASTERISK_GPL_KEY;