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/config.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/module.h>
21 #include <asterisk/pbx.h>
22 #include <asterisk/options.h>
23 #include <asterisk/lock.h>
24 #include <asterisk/sched.h>
25 #include <asterisk/io.h>
26 #include <asterisk/rtp.h>
27 #include <asterisk/acl.h>
28 #include <asterisk/callerid.h>
29 #include <asterisk/file.h>
30 #include <asterisk/cli.h>
31 #include <asterisk/app.h>
32 #include <asterisk/musiconhold.h>
33 #include <asterisk/manager.h>
34 #include <asterisk/features.h>
35 #include <asterisk/utils.h>
36 #include <asterisk/causes.h>
37 #include <asterisk/astdb.h>
38 #include <sys/socket.h>
44 #include <arpa/inet.h>
45 #include <sys/signal.h>
47 static const char desc[] = "Agent Proxy Channel";
48 static const char channeltype[] = "Agent";
49 static const char tdesc[] = "Call Agent Proxy Channel";
50 static const char config[] = "agents.conf";
52 static const char app[] = "AgentLogin";
53 static const char app2[] = "AgentCallbackLogin";
54 static const char app3[] = "AgentMonitorOutgoing";
56 static const char synopsis[] = "Call agent login";
57 static const char synopsis2[] = "Call agent callback login";
58 static const char synopsis3[] = "Record agent's outgoing call";
60 static const 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 const 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";
77 static const char descrip3[] =
78 " AgentMonitorOutgoing([options]):\n"
79 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
80 "comparision of the callerid of the current interface and the global variable \n"
81 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
82 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
83 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
85 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
86 "the agentid are not specified it'll look for n+101 priority.\n"
88 " 'd' - make the app return -1 if there is an error condition and there is\n"
89 " no extension n+101\n"
90 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
91 " 'n' - don't generate the warnings when there is no callerid or the\n"
92 " agentid is not known.\n"
93 " It's handy if you want to have one context for agent and non-agent calls.\n";
95 static const char mandescr_agents[] =
96 "Description: Will list info about all possible agents.\n"
99 static char moh[80] = "default";
101 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
102 #define AST_MAX_BUF 256
103 #define AST_MAX_FILENAME_LEN 256
105 /* Persistent Agents astdb family */
106 static const char pa_family[] = "/Agents";
107 /* The maximum lengh of each persistent member agent database entry */
108 #define PA_MAX_LEN 2048
109 /* queues.conf [general] option */
110 static int persistent_agents = 0;
111 static void dump_agents(void);
113 static ast_group_t group;
114 static int autologoff;
115 static int wrapuptime;
118 static int maxlogintries = 3;
119 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
121 static int usecnt =0;
122 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
124 /* Protect the interface list (of pvt's) */
125 AST_MUTEX_DEFINE_STATIC(agentlock);
127 static int recordagentcalls = 0;
128 static char recordformat[AST_MAX_BUF] = "";
129 static char recordformatext[AST_MAX_BUF] = "";
130 static int createlink = 0;
131 static char urlprefix[AST_MAX_BUF] = "";
132 static char savecallsin[AST_MAX_BUF] = "";
133 static int updatecdr = 0;
134 static char beep[AST_MAX_BUF] = "beep";
136 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
138 static struct agent_pvt {
139 ast_mutex_t lock; /* Channel private lock */
140 int dead; /* Poised for destruction? */
141 int pending; /* Not a real agent -- just pending a match */
142 int abouttograb; /* About to grab */
143 int autologoff; /* Auto timeout time */
144 int ackcall; /* ackcall */
145 time_t loginstart; /* When agent first logged in (0 when logged off) */
146 time_t start; /* When call started */
147 struct timeval lastdisc; /* When last disconnected */
148 int wrapuptime; /* Wrapup time in ms */
149 ast_group_t group; /* Group memberships */
150 int acknowledged; /* Acknowledged */
151 char moh[80]; /* Which music on hold */
152 char agent[AST_MAX_AGENT]; /* Agent ID */
153 char password[AST_MAX_AGENT]; /* Password for Agent login */
154 char name[AST_MAX_AGENT];
155 ast_mutex_t app_lock; /* Synchronization between owning applications */
156 volatile pthread_t owning_app; /* Owning application thread id */
157 volatile int app_sleep_cond; /* Sleep condition for the login app */
158 struct ast_channel *owner; /* Agent */
160 struct ast_channel *chan; /* Channel we use */
161 struct agent_pvt *next; /* Agent */
164 #define CHECK_FORMATS(ast, p) do { \
166 if (ast->nativeformats != p->chan->nativeformats) { \
167 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
168 /* Native formats changed, reset things */ \
169 ast->nativeformats = p->chan->nativeformats; \
170 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
171 ast_set_read_format(ast, ast->readformat); \
172 ast_set_write_format(ast, ast->writeformat); \
174 if (p->chan->readformat != ast->rawreadformat) \
175 ast_set_read_format(p->chan, ast->rawreadformat); \
176 if (p->chan->writeformat != ast->rawwriteformat) \
177 ast_set_write_format(p->chan, ast->rawwriteformat); \
181 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
182 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
183 totally impractical combinations XXX */
185 #define CLEANUP(ast, p) do { \
188 for (x=0;x<AST_MAX_FDS;x++) {\
189 if (x != AST_MAX_FDS - 2) \
190 ast->fds[x] = p->chan->fds[x]; \
192 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
196 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
197 static int agent_devicestate(void *data);
198 static int agent_digit(struct ast_channel *ast, char digit);
199 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
200 static int agent_hangup(struct ast_channel *ast);
201 static int agent_answer(struct ast_channel *ast);
202 static struct ast_frame *agent_read(struct ast_channel *ast);
203 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
204 static int agent_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen);
205 static int agent_indicate(struct ast_channel *ast, int condition);
206 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
207 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
209 static const struct ast_channel_tech agent_tech = {
211 .description = tdesc,
213 .requester = agent_request,
214 .devicestate = agent_devicestate,
215 .send_digit = agent_digit,
217 .hangup = agent_hangup,
218 .answer = agent_answer,
220 .write = agent_write,
221 .send_html = agent_sendhtml,
222 .exception = agent_read,
223 .indicate = agent_indicate,
224 .fixup = agent_fixup,
225 .bridged_channel = agent_bridgedchannel,
228 static void agent_unlink(struct agent_pvt *agent)
230 struct agent_pvt *p, *prev;
236 prev->next = agent->next;
238 agents = agent->next;
246 static struct agent_pvt *add_agent(char *agent, int pending)
248 char tmp[AST_MAX_BUF] = "";
249 char *password=NULL, *name=NULL;
250 struct agent_pvt *p, *prev;
252 strncpy(tmp, agent, sizeof(tmp) - 1);
253 if ((password = strchr(tmp, ','))) {
256 while (*password < 33) password++;
258 if (password && (name = strchr(password, ','))) {
261 while (*name < 33) name++;
266 if (!pending && !strcmp(p->agent, tmp))
272 p = malloc(sizeof(struct agent_pvt));
274 memset(p, 0, sizeof(struct agent_pvt));
275 strncpy(p->agent, tmp, sizeof(p->agent) -1);
276 ast_mutex_init(&p->lock);
277 ast_mutex_init(&p->app_lock);
278 p->owning_app = (pthread_t) -1;
279 p->app_sleep_cond = 1;
281 p->pending = pending;
292 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
293 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
294 strncpy(p->moh, moh, sizeof(p->moh) - 1);
295 p->ackcall = ackcall;
296 p->autologoff = autologoff;
297 p->wrapuptime = wrapuptime;
305 static int agent_cleanup(struct agent_pvt *p)
307 struct ast_channel *chan = p->owner;
309 chan->tech_pvt = NULL;
310 p->app_sleep_cond = 1;
311 /* Release ownership of the agent to other threads (presumably running the login app). */
312 ast_mutex_unlock(&p->app_lock);
314 ast_channel_free(chan);
316 ast_mutex_destroy(&p->lock);
317 ast_mutex_destroy(&p->app_lock);
323 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
325 static int agent_answer(struct ast_channel *ast)
327 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
331 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
333 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
334 char filename[AST_MAX_BUF];
339 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
340 /* substitute . for - */
341 if ((pointer = strchr(filename, '.')))
343 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
344 ast_monitor_start(ast, recordformat, tmp, needlock);
345 ast_monitor_setjoinfiles(ast, 1);
346 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
348 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
351 ast->cdr = ast_cdr_alloc();
352 ast_cdr_setuserfield(ast, tmp2);
355 ast_log(LOG_ERROR, "Recording already started on that call.\n");
359 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
361 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
364 static struct ast_frame *agent_read(struct ast_channel *ast)
366 struct agent_pvt *p = ast->tech_pvt;
367 struct ast_frame *f = NULL;
368 static struct ast_frame null_frame = { AST_FRAME_NULL, };
369 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
370 ast_mutex_lock(&p->lock);
371 CHECK_FORMATS(ast, p);
373 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
374 if (ast->fdno == AST_MAX_FDS - 3)
375 p->chan->fdno = AST_MAX_FDS - 2;
377 p->chan->fdno = ast->fdno;
378 f = ast_read(p->chan);
382 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
384 /* Note that we don't hangup if it's not a callback because Asterisk will do it
385 for us when the PBX instance that called login finishes */
386 if (!ast_strlen_zero(p->loginchan)) {
387 p->chan->_bridge = NULL;
389 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
391 if (p->wrapuptime && p->acknowledged) {
392 gettimeofday(&p->lastdisc, NULL);
393 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
394 if (p->lastdisc.tv_usec > 1000000) {
395 p->lastdisc.tv_usec -= 1000000;
396 p->lastdisc.tv_sec++;
398 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
405 if (p->chan && f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
407 ast_log(LOG_DEBUG, "Got answer on %s\n", p->chan->name);
409 if (option_verbose > 2)
410 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
411 /* Don't pass answer along */
420 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
421 if (!p->acknowledged) {
422 if (option_verbose > 2)
423 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
429 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
430 /* * terminates call */
434 if (f && (f->frametype == AST_FRAME_VOICE) && !p->acknowledged) {
435 /* Don't pass along agent audio until call is acknowledged */
440 if (p->chan && !p->chan->_bridge) {
441 if (strcasecmp(p->chan->type, "Local")) {
442 p->chan->_bridge = ast;
444 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
447 ast_mutex_unlock(&p->lock);
448 if (recordagentcalls && f == &answer_frame)
449 agent_start_monitoring(ast,0);
453 static int agent_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen)
455 struct agent_pvt *p = ast->tech_pvt;
457 ast_mutex_lock(&p->lock);
459 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
460 ast_mutex_unlock(&p->lock);
464 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
466 struct agent_pvt *p = ast->tech_pvt;
468 CHECK_FORMATS(ast, p);
469 ast_mutex_lock(&p->lock);
471 if ((f->frametype != AST_FRAME_VOICE) ||
472 (f->subclass == p->chan->writeformat)) {
473 res = ast_write(p->chan, f);
475 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
481 ast_mutex_unlock(&p->lock);
485 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
487 struct agent_pvt *p = newchan->tech_pvt;
488 ast_mutex_lock(&p->lock);
489 if (p->owner != oldchan) {
490 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
491 ast_mutex_unlock(&p->lock);
495 ast_mutex_unlock(&p->lock);
499 static int agent_indicate(struct ast_channel *ast, int condition)
501 struct agent_pvt *p = ast->tech_pvt;
503 ast_mutex_lock(&p->lock);
505 res = ast_indicate(p->chan, condition);
508 ast_mutex_unlock(&p->lock);
512 static int agent_digit(struct ast_channel *ast, char digit)
514 struct agent_pvt *p = ast->tech_pvt;
516 ast_mutex_lock(&p->lock);
518 res = p->chan->tech->send_digit(p->chan, digit);
521 ast_mutex_unlock(&p->lock);
525 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
527 struct agent_pvt *p = ast->tech_pvt;
530 ast_mutex_lock(&p->lock);
534 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
535 newstate = AST_STATE_DIALING;
538 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
541 ast_mutex_unlock(&p->lock);
543 ast_setstate(ast, newstate);
545 } else if (!ast_strlen_zero(p->loginchan)) {
547 /* Call on this agent */
548 if (option_verbose > 2)
549 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
550 if (p->chan->cid.cid_num)
551 free(p->chan->cid.cid_num);
552 if (ast->cid.cid_num)
553 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
555 p->chan->cid.cid_num = NULL;
556 if (p->chan->cid.cid_name)
557 free(p->chan->cid.cid_name);
558 if (ast->cid.cid_name)
559 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
561 p->chan->cid.cid_name = NULL;
562 ast_channel_inherit_variables(ast, p->chan);
563 res = ast_call(p->chan, p->loginchan, 0);
565 ast_mutex_unlock(&p->lock);
568 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
569 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
570 res = ast_streamfile(p->chan, beep, p->chan->language);
571 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
573 res = ast_waitstream(p->chan, "");
574 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
577 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
578 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
580 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
587 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
588 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
590 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
594 /* Call is immediately up, or might need ack */
596 newstate = AST_STATE_RINGING;
598 newstate = AST_STATE_UP;
599 if (recordagentcalls)
600 agent_start_monitoring(ast,0);
606 ast_mutex_unlock(&p->lock);
608 ast_setstate(ast, newstate);
612 static int agent_hangup(struct ast_channel *ast)
614 struct agent_pvt *p = ast->tech_pvt;
616 ast_mutex_lock(&p->lock);
618 ast->tech_pvt = NULL;
619 p->app_sleep_cond = 1;
622 /* if they really are hung up then set start to 0 so the test
623 * later if we're called on an already downed channel
624 * doesn't cause an agent to be logged out like when
625 * agent_request() is followed immediately by agent_hangup()
626 * as in apps/app_chanisavail.c:chanavail_exec()
629 ast_mutex_lock(&usecnt_lock);
631 ast_mutex_unlock(&usecnt_lock);
633 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
634 if (p->start && (ast->_state != AST_STATE_UP)) {
635 howlong = time(NULL) - p->start;
637 } else if (ast->_state == AST_STATE_RESERVED) {
642 /* If they're dead, go ahead and hang up on the agent now */
643 if (!ast_strlen_zero(p->loginchan)) {
644 /* Store last disconnect time */
645 if (p->wrapuptime && p->acknowledged) {
646 gettimeofday(&p->lastdisc, NULL);
647 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
648 if (p->lastdisc.tv_usec >= 1000000) {
649 p->lastdisc.tv_usec -= 1000000;
650 p->lastdisc.tv_sec++;
652 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
654 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
656 /* Recognize the hangup and pass it along immediately */
660 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
661 if (howlong && p->autologoff && (howlong > p->autologoff)) {
662 char agent[AST_MAX_AGENT] = "";
663 long logintime = time(NULL) - p->loginstart;
665 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
666 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
670 "Reason: Autologoff\r\n"
672 p->agent, p->loginchan, logintime, ast->uniqueid);
673 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
674 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
675 p->loginchan[0] = '\0';
676 ast_device_state_changed("Agent/%s", p->agent);
678 } else if (p->dead) {
679 ast_mutex_lock(&p->chan->lock);
680 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
681 ast_mutex_unlock(&p->chan->lock);
683 ast_mutex_lock(&p->chan->lock);
684 ast_moh_start(p->chan, p->moh);
685 ast_mutex_unlock(&p->chan->lock);
689 ast_mutex_unlock(&p->lock);
690 /* Release ownership of the agent to other threads (presumably running the login app). */
691 ast_mutex_unlock(&p->app_lock);
692 } else if (p->dead) {
693 /* Go ahead and lose it */
694 ast_mutex_unlock(&p->lock);
695 /* Release ownership of the agent to other threads (presumably running the login app). */
696 ast_mutex_unlock(&p->app_lock);
698 ast_mutex_unlock(&p->lock);
699 /* Release ownership of the agent to other threads (presumably running the login app). */
700 ast_mutex_unlock(&p->app_lock);
703 ast_mutex_unlock(&p->lock);
706 ast_mutex_lock(&agentlock);
708 ast_mutex_unlock(&agentlock);
710 if (p->abouttograb) {
711 /* Let the "about to grab" thread know this isn't valid anymore, and let it
714 } else if (p->dead) {
715 ast_mutex_destroy(&p->lock);
716 ast_mutex_destroy(&p->app_lock);
720 /* Not dead -- check availability now */
721 ast_mutex_lock(&p->lock);
722 /* Store last disconnect time */
723 gettimeofday(&p->lastdisc, NULL);
724 ast_mutex_unlock(&p->lock);
726 /* Release ownership of the agent to other threads (presumably running the login app). */
727 ast_mutex_unlock(&p->app_lock);
732 static int agent_cont_sleep( void *data )
738 p = (struct agent_pvt *)data;
740 ast_mutex_lock(&p->lock);
741 res = p->app_sleep_cond;
742 if (p->lastdisc.tv_sec) {
743 gettimeofday(&tv, NULL);
744 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
745 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
748 ast_mutex_unlock(&p->lock);
751 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
756 static int agent_ack_sleep( void *data )
763 /* Wait a second and look for something */
765 p = (struct agent_pvt *)data;
768 to = ast_waitfor(p->chan, to);
777 f = ast_read(p->chan);
782 if (f->frametype == AST_FRAME_DTMF)
787 ast_mutex_lock(&p->lock);
788 if (!p->app_sleep_cond) {
789 ast_mutex_unlock(&p->lock);
792 } else if (res == '#') {
793 ast_mutex_unlock(&p->lock);
797 ast_mutex_unlock(&p->lock);
805 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
808 struct ast_channel *ret=NULL;
811 p = bridge->tech_pvt;
813 ret = bridge->_bridge;
814 else if (chan == bridge->_bridge)
817 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
821 /*--- agent_new: Create new agent channel ---*/
822 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
824 struct ast_channel *tmp;
825 struct ast_frame null_frame = { AST_FRAME_NULL };
828 ast_log(LOG_WARNING, "No channel? :(\n");
832 tmp = ast_channel_alloc(0);
834 tmp->tech = &agent_tech;
836 tmp->nativeformats = p->chan->nativeformats;
837 tmp->writeformat = p->chan->writeformat;
838 tmp->rawwriteformat = p->chan->writeformat;
839 tmp->readformat = p->chan->readformat;
840 tmp->rawreadformat = p->chan->readformat;
841 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
842 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
843 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
845 tmp->nativeformats = AST_FORMAT_SLINEAR;
846 tmp->writeformat = AST_FORMAT_SLINEAR;
847 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
848 tmp->readformat = AST_FORMAT_SLINEAR;
849 tmp->rawreadformat = AST_FORMAT_SLINEAR;
852 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
854 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
855 tmp->type = channeltype;
856 /* Safe, agentlock already held */
857 ast_setstate(tmp, state);
860 ast_mutex_lock(&usecnt_lock);
862 ast_mutex_unlock(&usecnt_lock);
863 ast_update_use_count();
865 /* Wake up and wait for other applications (by definition the login app)
866 * to release this channel). Takes ownership of the agent channel
867 * to this thread only.
868 * For signalling the other thread, ast_queue_frame is used until we
869 * can safely use signals for this purpose. The pselect() needs to be
870 * implemented in the kernel for this.
872 p->app_sleep_cond = 0;
873 if( ast_mutex_trylock(&p->app_lock) )
876 ast_queue_frame(p->chan, &null_frame);
877 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
878 ast_mutex_lock(&p->app_lock);
879 ast_mutex_lock(&p->lock);
883 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
885 tmp->tech_pvt = NULL;
886 p->app_sleep_cond = 1;
887 ast_channel_free( tmp );
888 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
889 ast_mutex_unlock(&p->app_lock);
893 p->owning_app = pthread_self();
894 /* After the above step, there should not be any blockers. */
896 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
897 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
900 ast_moh_stop(p->chan);
903 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
908 /*--- read_agent_config: Read configuration data (agents.conf) ---*/
909 static int read_agent_config(void)
911 struct ast_config *cfg;
912 struct ast_variable *v;
913 struct agent_pvt *p, *pl, *pn;
920 cfg = ast_config_load(config);
922 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
925 ast_mutex_lock(&agentlock);
931 strncpy(moh, "default", sizeof(moh) - 1);
932 /* set the default recording values */
933 recordagentcalls = 0;
935 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
936 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
938 savecallsin[0] = '\0';
940 /* Read in [general] section for persistance */
941 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
942 persistent_agents = ast_true(general_val);
944 /* Read in the [agents] section */
945 v = ast_variable_browse(cfg, "agents");
947 /* Create the interface list */
948 if (!strcasecmp(v->name, "agent")) {
949 add_agent(v->value, 0);
950 } else if (!strcasecmp(v->name, "group")) {
951 group = ast_get_group(v->value);
952 } else if (!strcasecmp(v->name, "autologoff")) {
953 autologoff = atoi(v->value);
956 } else if (!strcasecmp(v->name, "ackcall")) {
957 if (!strcasecmp(v->value, "always"))
959 else if (ast_true(v->value))
963 } else if (!strcasecmp(v->name, "wrapuptime")) {
964 wrapuptime = atoi(v->value);
967 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
968 maxlogintries = atoi(v->value);
969 if (maxlogintries < 0)
971 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
972 strcpy(agentgoodbye,v->value);
973 } else if (!strcasecmp(v->name, "musiconhold")) {
974 strncpy(moh, v->value, sizeof(moh) - 1);
975 } else if (!strcasecmp(v->name, "updatecdr")) {
976 if (ast_true(v->value))
980 } else if (!strcasecmp(v->name, "recordagentcalls")) {
981 recordagentcalls = ast_true(v->value);
982 } else if (!strcasecmp(v->name, "createlink")) {
983 createlink = ast_true(v->value);
984 } else if (!strcasecmp(v->name, "recordformat")) {
985 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
986 if (!strcasecmp(v->value, "wav49"))
987 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
989 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
990 } else if (!strcasecmp(v->name, "urlprefix")) {
991 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
992 if (urlprefix[strlen(urlprefix) - 1] != '/')
993 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
994 } else if (!strcasecmp(v->name, "savecallsin")) {
995 if (v->value[0] == '/')
996 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
998 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
999 if (savecallsin[strlen(savecallsin) - 1] != '/')
1000 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1001 } else if (!strcasecmp(v->name, "custom_beep")) {
1002 strncpy(beep, v->value, sizeof(beep) - 1);
1016 /* Destroy if appropriate */
1019 ast_mutex_destroy(&p->lock);
1020 ast_mutex_destroy(&p->app_lock);
1023 /* Cause them to hang up */
1024 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1031 ast_mutex_unlock(&agentlock);
1032 ast_config_destroy(cfg);
1036 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1038 struct ast_channel *chan=NULL, *parent=NULL;
1039 struct agent_pvt *p;
1043 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1045 ast_mutex_lock(&agentlock);
1048 if (p == newlyavailable) {
1052 ast_mutex_lock(&p->lock);
1053 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1055 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1056 /* We found a pending call, time to merge */
1057 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1060 ast_mutex_unlock(&p->lock);
1063 ast_mutex_unlock(&p->lock);
1067 ast_mutex_unlock(&agentlock);
1068 if (parent && chan) {
1069 if (newlyavailable->ackcall > 1) {
1070 /* Don't do beep here */
1073 if (option_debug > 2)
1074 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1075 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1076 if (option_debug > 2)
1077 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1079 res = ast_waitstream(newlyavailable->chan, "");
1080 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1084 /* Note -- parent may have disappeared */
1085 if (p->abouttograb) {
1086 newlyavailable->acknowledged = 1;
1087 /* Safe -- agent lock already held */
1088 ast_setstate(parent, AST_STATE_UP);
1089 ast_setstate(chan, AST_STATE_UP);
1090 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1091 /* Go ahead and mark the channel as a zombie so that masquerade will
1092 destroy it for us, and we need not call ast_hangup */
1093 ast_mutex_lock(&parent->lock);
1094 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1095 ast_channel_masquerade(parent, chan);
1096 ast_mutex_unlock(&parent->lock);
1100 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1101 agent_cleanup(newlyavailable);
1105 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1106 agent_cleanup(newlyavailable);
1112 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1114 struct agent_pvt *p;
1117 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1119 ast_mutex_lock(&agentlock);
1122 if (p == newlyavailable) {
1126 ast_mutex_lock(&p->lock);
1127 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1129 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1130 ast_mutex_unlock(&p->lock);
1133 ast_mutex_unlock(&p->lock);
1137 ast_mutex_unlock(&agentlock);
1139 ast_mutex_unlock(&newlyavailable->lock);
1140 if (option_debug > 2)
1141 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1142 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1143 if (option_debug > 2)
1144 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1146 res = ast_waitstream(newlyavailable->chan, "");
1148 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1150 ast_mutex_lock(&newlyavailable->lock);
1155 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1156 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1158 struct agent_pvt *p;
1159 struct ast_channel *chan = NULL;
1161 ast_group_t groupmatch;
1168 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1169 groupmatch = (1 << groupoff);
1170 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1171 groupmatch = (1 << groupoff);
1177 /* Check actual logged in agents first */
1178 ast_mutex_lock(&agentlock);
1181 ast_mutex_lock(&p->lock);
1182 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1183 ast_strlen_zero(p->loginchan)) {
1186 if (!p->lastdisc.tv_sec) {
1187 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1188 if (!p->owner && p->chan) {
1190 chan = agent_new(p, AST_STATE_DOWN);
1193 ast_mutex_unlock(&p->lock);
1198 ast_mutex_unlock(&p->lock);
1204 ast_mutex_lock(&p->lock);
1205 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1206 if (p->chan || !ast_strlen_zero(p->loginchan))
1208 gettimeofday(&tv, NULL);
1210 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1212 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1213 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1214 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1215 if (!p->owner && p->chan) {
1216 /* Could still get a fixed agent */
1217 chan = agent_new(p, AST_STATE_DOWN);
1218 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1219 /* Adjustable agent */
1220 p->chan = ast_request("Local", format, p->loginchan, cause);
1222 chan = agent_new(p, AST_STATE_DOWN);
1225 ast_mutex_unlock(&p->lock);
1230 ast_mutex_unlock(&p->lock);
1235 if (!chan && waitforagent) {
1236 /* No agent available -- but we're requesting to wait for one.
1237 Allocate a place holder */
1240 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1241 p = add_agent(data, 1);
1242 p->group = groupmatch;
1243 chan = agent_new(p, AST_STATE_DOWN);
1245 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1248 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1251 *cause = AST_CAUSE_BUSY;
1253 *cause = AST_CAUSE_UNREGISTERED;
1254 ast_mutex_unlock(&agentlock);
1258 static int powerof(unsigned int v)
1261 for (x=0;x<32;x++) {
1262 if (v & (1 << x)) return x;
1267 /*--- action_agents: Manager routine for listing channels */
1268 static int action_agents(struct mansession *s, struct message *m)
1270 struct agent_pvt *p;
1271 char *username = NULL;
1272 char *loginChan = NULL;
1273 char *talkingtoChan = NULL;
1274 char *status = NULL;
1276 ast_mutex_lock(&agentlock);
1279 ast_mutex_lock(&p->lock);
1282 AGENT_LOGGEDOFF - Agent isn't logged in
1283 AGENT_IDLE - Agent is logged in, and waiting for call
1284 AGENT_ONCALL - Agent is logged in, and on a call
1285 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1287 if(!ast_strlen_zero(p->name)) {
1293 /* Set a default status. It 'should' get changed. */
1294 status = "AGENT_UNKNOWN";
1297 loginChan = p->loginchan;
1298 if(p->owner && p->owner->_bridge) {
1299 talkingtoChan = p->chan->cid.cid_num;
1300 status = "AGENT_ONCALL";
1302 talkingtoChan = "n/a";
1303 status = "AGENT_IDLE";
1305 } else if(!ast_strlen_zero(p->loginchan)) {
1306 loginChan = p->loginchan;
1307 talkingtoChan = "n/a";
1308 status = "AGENT_IDLE";
1309 if(p->acknowledged) {
1310 sprintf(loginChan, " %s (Confirmed)", loginChan);
1314 talkingtoChan = "n/a";
1315 status = "AGENT_LOGGEDOFF";
1318 ast_cli(s->fd, "Event: Agents\r\n"
1322 "LoggedInChan: %s\r\n"
1323 "LoggedInTime: %ld\r\n"
1326 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1327 ast_mutex_unlock(&p->lock);
1330 ast_mutex_unlock(&agentlock);
1334 static int agent_logoff_cmd(int fd, int argc, char **argv)
1336 struct agent_pvt *p;
1337 char *agent = argv[2] + 6;
1340 if (argc < 3 || argc > 4)
1341 return RESULT_SHOWUSAGE;
1342 if (argc == 4 && strcasecmp(argv[3], "soft"))
1343 return RESULT_SHOWUSAGE;
1345 for (p=agents; p; p=p->next) {
1346 if (!strcasecmp(p->agent, agent)) {
1349 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1352 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1355 logintime = time(NULL) - p->loginstart;
1358 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1361 "Logintime: %ld\r\n",
1362 p->agent, p->loginchan, logintime);
1363 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1364 p->loginchan[0] = '\0';
1365 ast_cli(fd, "Logging out %s\n", agent);
1366 ast_device_state_changed("Agent/%s", p->agent);
1367 if (persistent_agents)
1372 return RESULT_SUCCESS;
1375 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1377 struct agent_pvt *p;
1378 char name[AST_MAX_AGENT];
1382 for (p=agents; p; p=p->next) {
1383 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1384 if (!strncasecmp(word, name, strlen(word))) {
1385 if (++which > state) {
1386 return strdup(name);
1390 } else if (pos == 3 && state == 0) {
1391 return strdup("soft");
1396 /*--- agents_show: Show agents in cli ---*/
1397 static int agents_show(int fd, int argc, char **argv)
1399 struct agent_pvt *p;
1400 char username[AST_MAX_BUF];
1401 char location[AST_MAX_BUF] = "";
1402 char talkingto[AST_MAX_BUF] = "";
1403 char moh[AST_MAX_BUF];
1406 return RESULT_SHOWUSAGE;
1407 ast_mutex_lock(&agentlock);
1410 ast_mutex_lock(&p->lock);
1413 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1415 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1417 if (!ast_strlen_zero(p->name))
1418 snprintf(username, sizeof(username), "(%s) ", p->name);
1422 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1423 if (p->owner && ast_bridged_channel(p->owner)) {
1424 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1426 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1428 } else if (!ast_strlen_zero(p->loginchan)) {
1429 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1430 talkingto[0] = '\0';
1431 if (p->acknowledged)
1432 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1434 strncpy(location, "not logged in", sizeof(location) - 1);
1435 talkingto[0] = '\0';
1437 if (!ast_strlen_zero(p->moh))
1438 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1439 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1440 username, location, talkingto, moh);
1442 ast_mutex_unlock(&p->lock);
1445 ast_mutex_unlock(&agentlock);
1446 return RESULT_SUCCESS;
1449 static char show_agents_usage[] =
1450 "Usage: show agents\n"
1451 " Provides summary information on agents.\n";
1453 static char agent_logoff_usage[] =
1454 "Usage: agent logoff <channel> [soft]\n"
1455 " Sets an agent as no longer logged in.\n"
1456 " If 'soft' is specified, do not hangup existing calls.\n";
1458 static struct ast_cli_entry cli_show_agents = {
1459 { "show", "agents", NULL }, agents_show,
1460 "Show status of agents", show_agents_usage, NULL };
1462 static struct ast_cli_entry cli_agent_logoff = {
1463 { "agent", "logoff", NULL }, agent_logoff_cmd,
1464 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1466 STANDARD_LOCAL_USER;
1469 /*--- __login_exec: Log in agent application ---*/
1470 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1474 int max_login_tries = maxlogintries;
1475 struct agent_pvt *p;
1476 struct localuser *u;
1478 int login_state = 0;
1479 char user[AST_MAX_AGENT] = "";
1480 char pass[AST_MAX_AGENT];
1481 char agent[AST_MAX_AGENT] = "";
1482 char xpass[AST_MAX_AGENT] = "";
1485 char *opt_user = NULL;
1486 char *options = NULL;
1489 char *tmpoptions = NULL;
1490 char *context = NULL;
1492 int play_announcement = 1;
1493 char agent_goodbye[AST_MAX_FILENAME_LEN];
1494 int update_cdr = updatecdr;
1495 char *filename = "agent-loginok";
1497 strcpy(agent_goodbye, agentgoodbye);
1500 /* Parse the arguments XXX Check for failure XXX */
1501 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1503 /* Set Channel Specific Login Overrides */
1504 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1505 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1506 if (max_login_tries < 0)
1507 max_login_tries = 0;
1508 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1509 if (option_verbose > 2)
1510 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);
1512 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1513 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1517 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1518 if (option_verbose > 2)
1519 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1521 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1522 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1523 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1524 if (option_verbose > 2)
1525 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1527 /* End Channel Specific Login Overrides */
1528 /* Read command line options */
1530 options = strchr(opt_user, '|');
1535 context = strchr(options, '@');
1541 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1548 option = (char)options[0];
1549 if ((option >= 0) && (option <= '9'))
1555 play_announcement = 0;
1557 badoption[0] = option;
1558 badoption[1] = '\0';
1559 tmpoptions=badoption;
1560 if (option_verbose > 2)
1561 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1567 /* End command line options */
1569 if (chan->_state != AST_STATE_UP)
1570 res = ast_answer(chan);
1572 if( opt_user && !ast_strlen_zero(opt_user))
1573 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1575 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1577 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1579 /* Check for password */
1580 ast_mutex_lock(&agentlock);
1583 if (!strcmp(p->agent, user) && !p->pending)
1584 strncpy(xpass, p->password, sizeof(xpass) - 1);
1587 ast_mutex_unlock(&agentlock);
1589 if (!ast_strlen_zero(xpass))
1590 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1594 errmsg = "agent-incorrect";
1597 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1600 /* Check again for accuracy */
1601 ast_mutex_lock(&agentlock);
1604 ast_mutex_lock(&p->lock);
1605 if (!strcmp(p->agent, user) &&
1606 !strcmp(p->password, pass) && !p->pending) {
1607 login_state = 1; /* Successful Login */
1608 /* Set Channel Specific Agent Overides */
1609 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1610 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1612 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1616 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1617 if (option_verbose > 2)
1618 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1620 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1621 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1622 if (p->autologoff < 0)
1624 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1625 if (option_verbose > 2)
1626 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1628 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1629 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1630 if (p->wrapuptime < 0)
1632 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1633 if (option_verbose > 2)
1634 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1636 /* End Channel Specific Agent Overides */
1638 char last_loginchan[80] = "";
1640 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1643 char tmpchan[AST_MAX_BUF] = "";
1645 /* Retrieve login chan */
1648 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1651 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1652 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1656 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1660 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);
1661 res = ast_streamfile(chan, "invalid", chan->language);
1663 res = ast_waitstream(chan, AST_DIGIT_ANY);
1676 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1677 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1679 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1680 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1682 if (ast_strlen_zero(p->loginchan)) {
1684 filename = "agent-loggedoff";
1686 p->acknowledged = 0;
1687 /* store/clear the global variable that stores agentid based on the callerid */
1688 if (chan->cid.cid_num) {
1689 char agentvar[AST_MAX_BUF];
1690 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1691 if (ast_strlen_zero(p->loginchan))
1692 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1694 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1696 if(update_cdr && chan->cdr)
1697 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1701 p->loginchan[0] = '\0';
1702 p->acknowledged = 0;
1704 ast_mutex_unlock(&p->lock);
1705 ast_mutex_unlock(&agentlock);
1706 if( !res && play_announcement==1 )
1707 res = ast_streamfile(chan, filename, chan->language);
1709 ast_waitstream(chan, "");
1710 ast_mutex_lock(&agentlock);
1711 ast_mutex_lock(&p->lock);
1713 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1715 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1718 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1720 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1722 /* Check once more just in case */
1725 if (callbackmode && !res) {
1726 /* Just say goodbye and be done with it */
1727 if (!ast_strlen_zero(p->loginchan)) {
1728 if (p->loginstart == 0)
1729 time(&p->loginstart);
1730 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1734 p->agent, p->loginchan, chan->uniqueid);
1735 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1736 if (option_verbose > 1)
1737 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1738 ast_device_state_changed("Agent/%s", p->agent);
1740 logintime = time(NULL) - p->loginstart;
1742 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1745 "Logintime: %ld\r\n"
1747 p->agent, last_loginchan, logintime, chan->uniqueid);
1748 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1749 if (option_verbose > 1)
1750 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1751 ast_device_state_changed("Agent/%s", p->agent);
1753 ast_mutex_unlock(&agentlock);
1755 res = ast_safe_sleep(chan, 500);
1756 ast_mutex_unlock(&p->lock);
1757 if (persistent_agents)
1760 #ifdef HONOR_MUSIC_CLASS
1761 /* check if the moh class was changed with setmusiconhold */
1762 if (*(chan->musicclass))
1763 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1765 ast_moh_start(chan, p->moh);
1766 if (p->loginstart == 0)
1767 time(&p->loginstart);
1768 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1772 p->agent, chan->name, chan->uniqueid);
1773 if (update_cdr && chan->cdr)
1774 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1775 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1776 if (option_verbose > 1)
1777 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1778 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1779 /* Login this channel and wait for it to
1785 check_availability(p, 0);
1786 ast_mutex_unlock(&p->lock);
1787 ast_mutex_unlock(&agentlock);
1788 ast_device_state_changed("Agent/%s", p->agent);
1790 ast_mutex_lock(&p->lock);
1791 if (p->chan != chan)
1793 ast_mutex_unlock(&p->lock);
1794 /* Yield here so other interested threads can kick in. */
1799 ast_mutex_lock(&agentlock);
1800 ast_mutex_lock(&p->lock);
1801 if (p->lastdisc.tv_sec) {
1802 gettimeofday(&tv, NULL);
1803 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1804 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1806 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1807 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1811 check_availability(p, 0);
1814 ast_mutex_unlock(&p->lock);
1815 ast_mutex_unlock(&agentlock);
1816 /* Synchronize channel ownership between call to agent and itself. */
1817 ast_mutex_lock( &p->app_lock );
1818 ast_mutex_lock(&p->lock);
1819 p->owning_app = pthread_self();
1820 ast_mutex_unlock(&p->lock);
1822 res = agent_ack_sleep(p);
1824 res = ast_safe_sleep_conditional( chan, 1000,
1825 agent_cont_sleep, p );
1826 ast_mutex_unlock( &p->app_lock );
1827 if ((p->ackcall > 1) && (res == 1)) {
1828 ast_mutex_lock(&agentlock);
1829 ast_mutex_lock(&p->lock);
1830 check_availability(p, 0);
1831 ast_mutex_unlock(&p->lock);
1832 ast_mutex_unlock(&agentlock);
1837 ast_mutex_lock(&p->lock);
1838 if (res && p->owner)
1839 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1840 /* Log us off if appropriate */
1841 if (p->chan == chan)
1843 p->acknowledged = 0;
1844 logintime = time(NULL) - p->loginstart;
1846 ast_mutex_unlock(&p->lock);
1847 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1849 "Logintime: %ld\r\n"
1851 p->agent, logintime, chan->uniqueid);
1852 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1853 if (option_verbose > 1)
1854 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1855 /* If there is no owner, go ahead and kill it now */
1856 ast_device_state_changed("Agent/%s", p->agent);
1857 if (p->dead && !p->owner) {
1858 ast_mutex_destroy(&p->lock);
1859 ast_mutex_destroy(&p->app_lock);
1864 ast_mutex_unlock(&p->lock);
1869 ast_mutex_unlock(&p->lock);
1870 errmsg = "agent-alreadyon";
1875 ast_mutex_unlock(&p->lock);
1879 ast_mutex_unlock(&agentlock);
1881 if (!res && (max_login_tries==0 || tries < max_login_tries))
1882 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1885 LOCAL_USER_REMOVE(u);
1887 res = ast_safe_sleep(chan, 500);
1889 /* AgentLogin() exit */
1890 if (!callbackmode) {
1893 /* AgentCallbackLogin() exit*/
1896 if (login_state > 0) {
1897 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1898 if (login_state==1) {
1899 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1900 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1903 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1907 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1909 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1911 /* Do we need to play agent-goodbye now that we will be hanging up? */
1912 if (play_announcement==1) {
1914 res = ast_safe_sleep(chan, 1000);
1915 res = ast_streamfile(chan, agent_goodbye, chan->language);
1917 res = ast_waitstream(chan, "");
1919 res = ast_safe_sleep(chan, 1000);
1922 /* We should never get here if next priority exists when in callbackmode */
1926 static int login_exec(struct ast_channel *chan, void *data)
1928 return __login_exec(chan, data, 0);
1931 static int callback_exec(struct ast_channel *chan, void *data)
1933 return __login_exec(chan, data, 1);
1936 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1938 int exitifnoagentid = 0;
1940 int changeoutgoing = 0;
1942 char agent[AST_MAX_AGENT], *tmp;
1945 if (strchr(data, 'd'))
1946 exitifnoagentid = 1;
1947 if (strchr(data, 'n'))
1949 if (strchr(data, 'c'))
1952 if (chan->cid.cid_num) {
1953 char agentvar[AST_MAX_BUF];
1954 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1955 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1956 struct agent_pvt *p = agents;
1957 strncpy(agent, tmp, sizeof(agent) - 1);
1958 ast_mutex_lock(&agentlock);
1960 if (!strcasecmp(p->agent, tmp)) {
1961 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1962 __agent_start_monitoring(chan, p, 1);
1967 ast_mutex_unlock(&agentlock);
1972 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);
1977 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");
1979 /* check if there is n + 101 priority */
1981 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1982 chan->priority+=100;
1983 if (option_verbose > 2)
1984 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1986 else if (exitifnoagentid)
1992 /* Dump AgentCallbackLogin agents to the database for persistence
1995 static void dump_agents(void)
1997 struct agent_pvt *cur_agent = NULL;
1999 for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2000 if (cur_agent->chan)
2003 if (!ast_strlen_zero(cur_agent->loginchan)) {
2004 if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan))
2005 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2006 else if (option_debug)
2007 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2009 /* Delete - no agent or there is an error */
2010 ast_db_del(pa_family, cur_agent->agent);
2015 /* Reload the persistent agents from astdb */
2016 static void reload_agents(void)
2019 struct ast_db_entry *db_tree;
2020 struct ast_db_entry *entry;
2021 struct agent_pvt *cur_agent;
2022 char agent_data[80];
2024 db_tree = ast_db_gettree(pa_family, NULL);
2026 ast_mutex_lock(&agentlock);
2027 for (entry = db_tree; entry; entry = entry->next) {
2028 agent_num = entry->key + strlen(pa_family) + 2;
2031 ast_mutex_lock(&cur_agent->lock);
2032 if (strcmp(agent_num, cur_agent->agent) == 0)
2034 ast_mutex_unlock(&cur_agent->lock);
2035 cur_agent = cur_agent->next;
2038 ast_db_del(pa_family, agent_num);
2041 ast_mutex_unlock(&cur_agent->lock);
2042 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2044 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2045 strncpy(cur_agent->loginchan, agent_data, sizeof(cur_agent->loginchan)-1);
2046 if (cur_agent->loginstart == 0)
2047 time(&cur_agent->loginstart);
2048 ast_device_state_changed("Agent/%s", cur_agent->agent);
2051 ast_mutex_unlock(&agentlock);
2053 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2054 ast_db_freetree(db_tree);
2059 /*--- agent_devicestate: Part of PBX channel interface ---*/
2060 static int agent_devicestate(void *data)
2062 struct agent_pvt *p;
2064 ast_group_t groupmatch;
2067 int res = AST_DEVICE_INVALID;
2070 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2071 groupmatch = (1 << groupoff);
2072 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2073 groupmatch = (1 << groupoff);
2079 /* Check actual logged in agents first */
2080 ast_mutex_lock(&agentlock);
2083 ast_mutex_lock(&p->lock);
2084 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2086 if (res != AST_DEVICE_INUSE)
2087 res = AST_DEVICE_BUSY;
2089 if (res == AST_DEVICE_BUSY)
2090 res = AST_DEVICE_INUSE;
2091 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2092 if (res == AST_DEVICE_INVALID)
2093 res = AST_DEVICE_UNKNOWN;
2094 } else if (res == AST_DEVICE_INVALID)
2095 res = AST_DEVICE_UNAVAILABLE;
2097 if (!strcmp(data, p->agent)) {
2098 ast_mutex_unlock(&p->lock);
2102 ast_mutex_unlock(&p->lock);
2105 ast_mutex_unlock(&agentlock);
2109 /*--- load_module: Initialize channel module ---*/
2112 /* Make sure we can register our agent channel type */
2113 if (ast_channel_register(&agent_tech)) {
2114 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2117 /* Dialplan applications */
2118 ast_register_application(app, login_exec, synopsis, descrip);
2119 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2120 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2121 /* Manager command */
2122 ast_manager_register2("Agents", 0, action_agents, "Lists agents and their status", mandescr_agents);
2123 /* CLI Application */
2124 ast_cli_register(&cli_show_agents);
2125 ast_cli_register(&cli_agent_logoff);
2126 /* Read in the config */
2127 read_agent_config();
2128 if (persistent_agents)
2135 read_agent_config();
2136 if (persistent_agents)
2143 struct agent_pvt *p;
2144 /* First, take us out of the channel loop */
2145 /* Unregister CLI application */
2146 ast_cli_unregister(&cli_show_agents);
2147 ast_cli_unregister(&cli_agent_logoff);
2148 /* Unregister dialplan applications */
2149 ast_unregister_application(app);
2150 ast_unregister_application(app2);
2151 ast_unregister_application(app3);
2152 /* Unregister manager command */
2153 ast_manager_unregister("Agents");
2154 /* Unregister channel */
2155 ast_channel_unregister(&agent_tech);
2156 if (!ast_mutex_lock(&agentlock)) {
2157 /* Hangup all interfaces if they have an owner */
2161 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2165 ast_mutex_unlock(&agentlock);
2167 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2176 ast_mutex_lock(&usecnt_lock);
2178 ast_mutex_unlock(&usecnt_lock);
2184 return ASTERISK_GPL_KEY;
2189 return (char *) desc;