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, const 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;
298 /* If someone reduces the wrapuptime and reloads, we want it
299 * to change the wrapuptime immediately on all calls */
300 if (p->wrapuptime > wrapuptime) {
302 gettimeofday(&now, NULL);
304 /* We won't be pedantic and check the tv_usec val */
305 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
306 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
307 p->lastdisc.tv_usec = now.tv_usec;
310 p->wrapuptime = wrapuptime;
319 static int agent_cleanup(struct agent_pvt *p)
321 struct ast_channel *chan = p->owner;
323 chan->tech_pvt = NULL;
324 p->app_sleep_cond = 1;
325 /* Release ownership of the agent to other threads (presumably running the login app). */
326 ast_mutex_unlock(&p->app_lock);
328 ast_channel_free(chan);
330 ast_mutex_destroy(&p->lock);
331 ast_mutex_destroy(&p->app_lock);
337 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
339 static int agent_answer(struct ast_channel *ast)
341 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
345 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
347 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
348 char filename[AST_MAX_BUF];
353 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
354 /* substitute . for - */
355 if ((pointer = strchr(filename, '.')))
357 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
358 ast_monitor_start(ast, recordformat, tmp, needlock);
359 ast_monitor_setjoinfiles(ast, 1);
360 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
362 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
365 ast->cdr = ast_cdr_alloc();
366 ast_cdr_setuserfield(ast, tmp2);
369 ast_log(LOG_ERROR, "Recording already started on that call.\n");
373 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
375 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
378 static struct ast_frame *agent_read(struct ast_channel *ast)
380 struct agent_pvt *p = ast->tech_pvt;
381 struct ast_frame *f = NULL;
382 static struct ast_frame null_frame = { AST_FRAME_NULL, };
383 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
384 ast_mutex_lock(&p->lock);
385 CHECK_FORMATS(ast, p);
387 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
388 if (ast->fdno == AST_MAX_FDS - 3)
389 p->chan->fdno = AST_MAX_FDS - 2;
391 p->chan->fdno = ast->fdno;
392 f = ast_read(p->chan);
396 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
398 p->chan->_bridge = NULL;
399 /* Note that we don't hangup if it's not a callback because Asterisk will do it
400 for us when the PBX instance that called login finishes */
401 if (!ast_strlen_zero(p->loginchan)) {
403 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
405 if (p->wrapuptime && p->acknowledged) {
406 gettimeofday(&p->lastdisc, NULL);
407 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
408 if (p->lastdisc.tv_usec > 1000000) {
409 p->lastdisc.tv_usec -= 1000000;
410 p->lastdisc.tv_sec++;
412 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
419 /* if acknowledgement is not required, and the channel is up, we may have missed
420 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
421 if (!p->ackcall && !p->acknowledged && p->chan->_state == AST_STATE_UP)
423 switch (f->frametype) {
424 case AST_FRAME_CONTROL:
425 if (f->subclass == AST_CONTROL_ANSWER) {
427 if (option_verbose > 2)
428 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
429 /* Don't pass answer along */
438 if (!p->acknowledged && (f->subclass == '#')) {
439 if (option_verbose > 2)
440 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
444 } else if (f->subclass == '*') {
445 /* terminates call */
450 case AST_FRAME_VOICE:
451 /* don't pass voice until the call is acknowledged */
452 if (!p->acknowledged) {
461 if (p->chan && !p->chan->_bridge) {
462 if (strcasecmp(p->chan->type, "Local")) {
463 p->chan->_bridge = ast;
465 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
468 ast_mutex_unlock(&p->lock);
469 if (recordagentcalls && f == &answer_frame)
470 agent_start_monitoring(ast,0);
474 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
476 struct agent_pvt *p = ast->tech_pvt;
478 ast_mutex_lock(&p->lock);
480 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
481 ast_mutex_unlock(&p->lock);
485 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
487 struct agent_pvt *p = ast->tech_pvt;
489 CHECK_FORMATS(ast, p);
490 ast_mutex_lock(&p->lock);
492 if ((f->frametype != AST_FRAME_VOICE) ||
493 (f->subclass == p->chan->writeformat)) {
494 res = ast_write(p->chan, f);
496 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
502 ast_mutex_unlock(&p->lock);
506 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
508 struct agent_pvt *p = newchan->tech_pvt;
509 ast_mutex_lock(&p->lock);
510 if (p->owner != oldchan) {
511 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
512 ast_mutex_unlock(&p->lock);
516 ast_mutex_unlock(&p->lock);
520 static int agent_indicate(struct ast_channel *ast, int condition)
522 struct agent_pvt *p = ast->tech_pvt;
524 ast_mutex_lock(&p->lock);
526 res = ast_indicate(p->chan, condition);
529 ast_mutex_unlock(&p->lock);
533 static int agent_digit(struct ast_channel *ast, char digit)
535 struct agent_pvt *p = ast->tech_pvt;
537 ast_mutex_lock(&p->lock);
539 res = p->chan->tech->send_digit(p->chan, digit);
542 ast_mutex_unlock(&p->lock);
546 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
548 struct agent_pvt *p = ast->tech_pvt;
551 ast_mutex_lock(&p->lock);
555 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
556 newstate = AST_STATE_DIALING;
559 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
562 ast_mutex_unlock(&p->lock);
564 ast_setstate(ast, newstate);
566 } else if (!ast_strlen_zero(p->loginchan)) {
568 /* Call on this agent */
569 if (option_verbose > 2)
570 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
571 if (p->chan->cid.cid_num)
572 free(p->chan->cid.cid_num);
573 if (ast->cid.cid_num)
574 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
576 p->chan->cid.cid_num = NULL;
577 if (p->chan->cid.cid_name)
578 free(p->chan->cid.cid_name);
579 if (ast->cid.cid_name)
580 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
582 p->chan->cid.cid_name = NULL;
583 ast_channel_inherit_variables(ast, p->chan);
584 res = ast_call(p->chan, p->loginchan, 0);
586 ast_mutex_unlock(&p->lock);
589 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
590 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
591 res = ast_streamfile(p->chan, beep, p->chan->language);
592 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
594 res = ast_waitstream(p->chan, "");
595 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
598 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
599 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
601 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
608 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
609 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
611 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
615 /* Call is immediately up, or might need ack */
617 newstate = AST_STATE_RINGING;
619 newstate = AST_STATE_UP;
620 if (recordagentcalls)
621 agent_start_monitoring(ast,0);
627 ast_mutex_unlock(&p->lock);
629 ast_setstate(ast, newstate);
633 static int agent_hangup(struct ast_channel *ast)
635 struct agent_pvt *p = ast->tech_pvt;
637 ast_mutex_lock(&p->lock);
639 ast->tech_pvt = NULL;
640 p->app_sleep_cond = 1;
643 /* if they really are hung up then set start to 0 so the test
644 * later if we're called on an already downed channel
645 * doesn't cause an agent to be logged out like when
646 * agent_request() is followed immediately by agent_hangup()
647 * as in apps/app_chanisavail.c:chanavail_exec()
650 ast_mutex_lock(&usecnt_lock);
652 ast_mutex_unlock(&usecnt_lock);
654 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
655 if (p->start && (ast->_state != AST_STATE_UP)) {
656 howlong = time(NULL) - p->start;
658 } else if (ast->_state == AST_STATE_RESERVED) {
663 p->chan->_bridge = NULL;
664 /* If they're dead, go ahead and hang up on the agent now */
665 if (!ast_strlen_zero(p->loginchan)) {
666 /* Store last disconnect time */
667 if (p->wrapuptime && p->acknowledged) {
668 gettimeofday(&p->lastdisc, NULL);
669 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
670 if (p->lastdisc.tv_usec >= 1000000) {
671 p->lastdisc.tv_usec -= 1000000;
672 p->lastdisc.tv_sec++;
674 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
676 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
678 /* Recognize the hangup and pass it along immediately */
682 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
683 if (howlong && p->autologoff && (howlong > p->autologoff)) {
684 char agent[AST_MAX_AGENT] = "";
685 long logintime = time(NULL) - p->loginstart;
687 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
688 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
692 "Reason: Autologoff\r\n"
694 p->agent, p->loginchan, logintime, ast->uniqueid);
695 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
696 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
697 p->loginchan[0] = '\0';
698 ast_device_state_changed("Agent/%s", p->agent);
700 } else if (p->dead) {
701 ast_mutex_lock(&p->chan->lock);
702 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
703 ast_mutex_unlock(&p->chan->lock);
705 ast_device_state_changed("Agent/%s", p->agent);
706 ast_mutex_lock(&p->chan->lock);
707 ast_moh_start(p->chan, p->moh);
708 ast_mutex_unlock(&p->chan->lock);
712 ast_mutex_unlock(&p->lock);
713 /* Release ownership of the agent to other threads (presumably running the login app). */
714 ast_mutex_unlock(&p->app_lock);
715 } else if (p->dead) {
716 /* Go ahead and lose it */
717 ast_mutex_unlock(&p->lock);
718 /* Release ownership of the agent to other threads (presumably running the login app). */
719 ast_mutex_unlock(&p->app_lock);
721 ast_mutex_unlock(&p->lock);
722 /* Release ownership of the agent to other threads (presumably running the login app). */
723 ast_mutex_unlock(&p->app_lock);
726 ast_mutex_unlock(&p->lock);
729 ast_mutex_lock(&agentlock);
731 ast_mutex_unlock(&agentlock);
733 if (p->abouttograb) {
734 /* Let the "about to grab" thread know this isn't valid anymore, and let it
737 } else if (p->dead) {
738 ast_mutex_destroy(&p->lock);
739 ast_mutex_destroy(&p->app_lock);
743 /* Not dead -- check availability now */
744 ast_mutex_lock(&p->lock);
745 /* Store last disconnect time */
746 gettimeofday(&p->lastdisc, NULL);
747 ast_mutex_unlock(&p->lock);
749 /* Release ownership of the agent to other threads (presumably running the login app). */
750 ast_mutex_unlock(&p->app_lock);
755 static int agent_cont_sleep( void *data )
761 p = (struct agent_pvt *)data;
763 ast_mutex_lock(&p->lock);
764 res = p->app_sleep_cond;
765 if (p->lastdisc.tv_sec) {
766 gettimeofday(&tv, NULL);
767 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
768 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
771 ast_mutex_unlock(&p->lock);
774 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
779 static int agent_ack_sleep( void *data )
786 /* Wait a second and look for something */
788 p = (struct agent_pvt *)data;
791 to = ast_waitfor(p->chan, to);
800 f = ast_read(p->chan);
805 if (f->frametype == AST_FRAME_DTMF)
810 ast_mutex_lock(&p->lock);
811 if (!p->app_sleep_cond) {
812 ast_mutex_unlock(&p->lock);
815 } else if (res == '#') {
816 ast_mutex_unlock(&p->lock);
820 ast_mutex_unlock(&p->lock);
828 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
831 struct ast_channel *ret=NULL;
834 p = bridge->tech_pvt;
836 ret = bridge->_bridge;
837 else if (chan == bridge->_bridge)
840 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
844 /*--- agent_new: Create new agent channel ---*/
845 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
847 struct ast_channel *tmp;
848 struct ast_frame null_frame = { AST_FRAME_NULL };
851 ast_log(LOG_WARNING, "No channel? :(\n");
855 tmp = ast_channel_alloc(0);
857 tmp->tech = &agent_tech;
859 tmp->nativeformats = p->chan->nativeformats;
860 tmp->writeformat = p->chan->writeformat;
861 tmp->rawwriteformat = p->chan->writeformat;
862 tmp->readformat = p->chan->readformat;
863 tmp->rawreadformat = p->chan->readformat;
864 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
865 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
866 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
868 tmp->nativeformats = AST_FORMAT_SLINEAR;
869 tmp->writeformat = AST_FORMAT_SLINEAR;
870 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
871 tmp->readformat = AST_FORMAT_SLINEAR;
872 tmp->rawreadformat = AST_FORMAT_SLINEAR;
875 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
877 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
878 tmp->type = channeltype;
879 /* Safe, agentlock already held */
880 ast_setstate(tmp, state);
883 ast_mutex_lock(&usecnt_lock);
885 ast_mutex_unlock(&usecnt_lock);
886 ast_update_use_count();
888 /* Wake up and wait for other applications (by definition the login app)
889 * to release this channel). Takes ownership of the agent channel
890 * to this thread only.
891 * For signalling the other thread, ast_queue_frame is used until we
892 * can safely use signals for this purpose. The pselect() needs to be
893 * implemented in the kernel for this.
895 p->app_sleep_cond = 0;
896 if( ast_mutex_trylock(&p->app_lock) )
899 ast_queue_frame(p->chan, &null_frame);
900 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
901 ast_mutex_lock(&p->app_lock);
902 ast_mutex_lock(&p->lock);
906 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
908 tmp->tech_pvt = NULL;
909 p->app_sleep_cond = 1;
910 ast_channel_free( tmp );
911 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
912 ast_mutex_unlock(&p->app_lock);
916 p->owning_app = pthread_self();
917 /* After the above step, there should not be any blockers. */
919 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
920 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
923 ast_moh_stop(p->chan);
926 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
931 /*--- read_agent_config: Read configuration data (agents.conf) ---*/
932 static int read_agent_config(void)
934 struct ast_config *cfg;
935 struct ast_variable *v;
936 struct agent_pvt *p, *pl, *pn;
943 cfg = ast_config_load(config);
945 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
948 ast_mutex_lock(&agentlock);
954 strncpy(moh, "default", sizeof(moh) - 1);
955 /* set the default recording values */
956 recordagentcalls = 0;
958 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
959 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
961 savecallsin[0] = '\0';
963 /* Read in [general] section for persistance */
964 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
965 persistent_agents = ast_true(general_val);
967 /* Read in the [agents] section */
968 v = ast_variable_browse(cfg, "agents");
970 /* Create the interface list */
971 if (!strcasecmp(v->name, "agent")) {
972 add_agent(v->value, 0);
973 } else if (!strcasecmp(v->name, "group")) {
974 group = ast_get_group(v->value);
975 } else if (!strcasecmp(v->name, "autologoff")) {
976 autologoff = atoi(v->value);
979 } else if (!strcasecmp(v->name, "ackcall")) {
980 if (!strcasecmp(v->value, "always"))
982 else if (ast_true(v->value))
986 } else if (!strcasecmp(v->name, "wrapuptime")) {
987 wrapuptime = atoi(v->value);
990 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
991 maxlogintries = atoi(v->value);
992 if (maxlogintries < 0)
994 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
995 strcpy(agentgoodbye,v->value);
996 } else if (!strcasecmp(v->name, "musiconhold")) {
997 strncpy(moh, v->value, sizeof(moh) - 1);
998 } else if (!strcasecmp(v->name, "updatecdr")) {
999 if (ast_true(v->value))
1003 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1004 recordagentcalls = ast_true(v->value);
1005 } else if (!strcasecmp(v->name, "createlink")) {
1006 createlink = ast_true(v->value);
1007 } else if (!strcasecmp(v->name, "recordformat")) {
1008 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
1009 if (!strcasecmp(v->value, "wav49"))
1010 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
1012 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
1013 } else if (!strcasecmp(v->name, "urlprefix")) {
1014 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
1015 if (urlprefix[strlen(urlprefix) - 1] != '/')
1016 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1017 } else if (!strcasecmp(v->name, "savecallsin")) {
1018 if (v->value[0] == '/')
1019 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
1021 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1022 if (savecallsin[strlen(savecallsin) - 1] != '/')
1023 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1024 } else if (!strcasecmp(v->name, "custom_beep")) {
1025 strncpy(beep, v->value, sizeof(beep) - 1);
1039 /* Destroy if appropriate */
1042 ast_mutex_destroy(&p->lock);
1043 ast_mutex_destroy(&p->app_lock);
1046 /* Cause them to hang up */
1047 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1054 ast_mutex_unlock(&agentlock);
1055 ast_config_destroy(cfg);
1059 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1061 struct ast_channel *chan=NULL, *parent=NULL;
1062 struct agent_pvt *p;
1066 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1068 ast_mutex_lock(&agentlock);
1071 if (p == newlyavailable) {
1075 ast_mutex_lock(&p->lock);
1076 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1078 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1079 /* We found a pending call, time to merge */
1080 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1083 ast_mutex_unlock(&p->lock);
1086 ast_mutex_unlock(&p->lock);
1090 ast_mutex_unlock(&agentlock);
1091 if (parent && chan) {
1092 if (newlyavailable->ackcall > 1) {
1093 /* Don't do beep here */
1096 if (option_debug > 2)
1097 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1098 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1099 if (option_debug > 2)
1100 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1102 res = ast_waitstream(newlyavailable->chan, "");
1103 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1107 /* Note -- parent may have disappeared */
1108 if (p->abouttograb) {
1109 newlyavailable->acknowledged = 1;
1110 /* Safe -- agent lock already held */
1111 ast_setstate(parent, AST_STATE_UP);
1112 ast_setstate(chan, AST_STATE_UP);
1113 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1114 /* Go ahead and mark the channel as a zombie so that masquerade will
1115 destroy it for us, and we need not call ast_hangup */
1116 ast_mutex_lock(&parent->lock);
1117 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1118 ast_channel_masquerade(parent, chan);
1119 ast_mutex_unlock(&parent->lock);
1123 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1124 agent_cleanup(newlyavailable);
1128 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1129 agent_cleanup(newlyavailable);
1135 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1137 struct agent_pvt *p;
1140 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1142 ast_mutex_lock(&agentlock);
1145 if (p == newlyavailable) {
1149 ast_mutex_lock(&p->lock);
1150 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1152 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1153 ast_mutex_unlock(&p->lock);
1156 ast_mutex_unlock(&p->lock);
1160 ast_mutex_unlock(&agentlock);
1162 ast_mutex_unlock(&newlyavailable->lock);
1163 if (option_debug > 2)
1164 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1165 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1166 if (option_debug > 2)
1167 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1169 res = ast_waitstream(newlyavailable->chan, "");
1171 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1173 ast_mutex_lock(&newlyavailable->lock);
1178 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1179 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1181 struct agent_pvt *p;
1182 struct ast_channel *chan = NULL;
1184 ast_group_t groupmatch;
1191 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1192 groupmatch = (1 << groupoff);
1193 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1194 groupmatch = (1 << groupoff);
1200 /* Check actual logged in agents first */
1201 ast_mutex_lock(&agentlock);
1204 ast_mutex_lock(&p->lock);
1205 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1206 ast_strlen_zero(p->loginchan)) {
1209 if (!p->lastdisc.tv_sec) {
1210 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1211 if (!p->owner && p->chan) {
1213 chan = agent_new(p, AST_STATE_DOWN);
1216 ast_mutex_unlock(&p->lock);
1221 ast_mutex_unlock(&p->lock);
1227 ast_mutex_lock(&p->lock);
1228 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1229 if (p->chan || !ast_strlen_zero(p->loginchan))
1231 gettimeofday(&tv, NULL);
1233 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1235 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1236 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1237 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1238 if (!p->owner && p->chan) {
1239 /* Could still get a fixed agent */
1240 chan = agent_new(p, AST_STATE_DOWN);
1241 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1242 /* Adjustable agent */
1243 p->chan = ast_request("Local", format, p->loginchan, cause);
1245 chan = agent_new(p, AST_STATE_DOWN);
1248 ast_mutex_unlock(&p->lock);
1253 ast_mutex_unlock(&p->lock);
1258 if (!chan && waitforagent) {
1259 /* No agent available -- but we're requesting to wait for one.
1260 Allocate a place holder */
1263 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1264 p = add_agent(data, 1);
1265 p->group = groupmatch;
1266 chan = agent_new(p, AST_STATE_DOWN);
1268 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1271 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1274 *cause = AST_CAUSE_BUSY;
1276 *cause = AST_CAUSE_UNREGISTERED;
1277 ast_mutex_unlock(&agentlock);
1281 static int powerof(unsigned int v)
1284 for (x=0;x<32;x++) {
1285 if (v & (1 << x)) return x;
1290 /*--- action_agents: Manager routine for listing channels */
1291 static int action_agents(struct mansession *s, struct message *m)
1293 struct agent_pvt *p;
1294 char *username = NULL;
1295 char *loginChan = NULL;
1296 char *talkingtoChan = NULL;
1297 char *status = NULL;
1299 ast_mutex_lock(&agentlock);
1302 ast_mutex_lock(&p->lock);
1305 AGENT_LOGGEDOFF - Agent isn't logged in
1306 AGENT_IDLE - Agent is logged in, and waiting for call
1307 AGENT_ONCALL - Agent is logged in, and on a call
1308 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1310 if(!ast_strlen_zero(p->name)) {
1316 /* Set a default status. It 'should' get changed. */
1317 status = "AGENT_UNKNOWN";
1320 loginChan = p->loginchan;
1321 if(p->owner && p->owner->_bridge) {
1322 talkingtoChan = p->chan->cid.cid_num;
1323 status = "AGENT_ONCALL";
1325 talkingtoChan = "n/a";
1326 status = "AGENT_IDLE";
1328 } else if(!ast_strlen_zero(p->loginchan)) {
1329 loginChan = p->loginchan;
1330 talkingtoChan = "n/a";
1331 status = "AGENT_IDLE";
1332 if(p->acknowledged) {
1333 sprintf(loginChan, " %s (Confirmed)", loginChan);
1337 talkingtoChan = "n/a";
1338 status = "AGENT_LOGGEDOFF";
1341 ast_cli(s->fd, "Event: Agents\r\n"
1345 "LoggedInChan: %s\r\n"
1346 "LoggedInTime: %ld\r\n"
1349 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1350 ast_mutex_unlock(&p->lock);
1353 ast_mutex_unlock(&agentlock);
1357 static int agent_logoff_cmd(int fd, int argc, char **argv)
1359 struct agent_pvt *p;
1360 char *agent = argv[2] + 6;
1363 if (argc < 3 || argc > 4)
1364 return RESULT_SHOWUSAGE;
1365 if (argc == 4 && strcasecmp(argv[3], "soft"))
1366 return RESULT_SHOWUSAGE;
1368 for (p=agents; p; p=p->next) {
1369 if (!strcasecmp(p->agent, agent)) {
1372 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1375 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1378 logintime = time(NULL) - p->loginstart;
1381 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1384 "Logintime: %ld\r\n",
1385 p->agent, p->loginchan, logintime);
1386 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1387 p->loginchan[0] = '\0';
1388 ast_cli(fd, "Logging out %s\n", agent);
1389 ast_device_state_changed("Agent/%s", p->agent);
1390 if (persistent_agents)
1395 return RESULT_SUCCESS;
1398 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1400 struct agent_pvt *p;
1401 char name[AST_MAX_AGENT];
1405 for (p=agents; p; p=p->next) {
1406 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1407 if (!strncasecmp(word, name, strlen(word))) {
1408 if (++which > state) {
1409 return strdup(name);
1413 } else if (pos == 3 && state == 0) {
1414 return strdup("soft");
1419 /*--- agents_show: Show agents in cli ---*/
1420 static int agents_show(int fd, int argc, char **argv)
1422 struct agent_pvt *p;
1423 char username[AST_MAX_BUF];
1424 char location[AST_MAX_BUF] = "";
1425 char talkingto[AST_MAX_BUF] = "";
1426 char moh[AST_MAX_BUF];
1429 return RESULT_SHOWUSAGE;
1430 ast_mutex_lock(&agentlock);
1433 ast_mutex_lock(&p->lock);
1436 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1438 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1440 if (!ast_strlen_zero(p->name))
1441 snprintf(username, sizeof(username), "(%s) ", p->name);
1445 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1446 if (p->owner && ast_bridged_channel(p->owner)) {
1447 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1449 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1451 } else if (!ast_strlen_zero(p->loginchan)) {
1452 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1453 talkingto[0] = '\0';
1454 if (p->acknowledged)
1455 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1457 strncpy(location, "not logged in", sizeof(location) - 1);
1458 talkingto[0] = '\0';
1460 if (!ast_strlen_zero(p->moh))
1461 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1462 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1463 username, location, talkingto, moh);
1465 ast_mutex_unlock(&p->lock);
1468 ast_mutex_unlock(&agentlock);
1469 return RESULT_SUCCESS;
1472 static char show_agents_usage[] =
1473 "Usage: show agents\n"
1474 " Provides summary information on agents.\n";
1476 static char agent_logoff_usage[] =
1477 "Usage: agent logoff <channel> [soft]\n"
1478 " Sets an agent as no longer logged in.\n"
1479 " If 'soft' is specified, do not hangup existing calls.\n";
1481 static struct ast_cli_entry cli_show_agents = {
1482 { "show", "agents", NULL }, agents_show,
1483 "Show status of agents", show_agents_usage, NULL };
1485 static struct ast_cli_entry cli_agent_logoff = {
1486 { "agent", "logoff", NULL }, agent_logoff_cmd,
1487 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1489 STANDARD_LOCAL_USER;
1492 /*--- __login_exec: Log in agent application ---*/
1493 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1497 int max_login_tries = maxlogintries;
1498 struct agent_pvt *p;
1499 struct localuser *u;
1501 int login_state = 0;
1502 char user[AST_MAX_AGENT] = "";
1503 char pass[AST_MAX_AGENT];
1504 char agent[AST_MAX_AGENT] = "";
1505 char xpass[AST_MAX_AGENT] = "";
1508 char *opt_user = NULL;
1509 char *options = NULL;
1512 char *tmpoptions = NULL;
1513 char *context = NULL;
1515 int play_announcement = 1;
1516 char agent_goodbye[AST_MAX_FILENAME_LEN];
1517 int update_cdr = updatecdr;
1518 char *filename = "agent-loginok";
1520 strcpy(agent_goodbye, agentgoodbye);
1523 /* Parse the arguments XXX Check for failure XXX */
1524 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1526 /* Set Channel Specific Login Overrides */
1527 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1528 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1529 if (max_login_tries < 0)
1530 max_login_tries = 0;
1531 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1532 if (option_verbose > 2)
1533 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);
1535 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1536 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1540 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1541 if (option_verbose > 2)
1542 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1544 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1545 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1546 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1547 if (option_verbose > 2)
1548 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1550 /* End Channel Specific Login Overrides */
1551 /* Read command line options */
1553 options = strchr(opt_user, '|');
1558 context = strchr(options, '@');
1564 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1571 option = (char)options[0];
1572 if ((option >= 0) && (option <= '9'))
1578 play_announcement = 0;
1580 badoption[0] = option;
1581 badoption[1] = '\0';
1582 tmpoptions=badoption;
1583 if (option_verbose > 2)
1584 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1590 /* End command line options */
1592 if (chan->_state != AST_STATE_UP)
1593 res = ast_answer(chan);
1595 if( opt_user && !ast_strlen_zero(opt_user))
1596 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1598 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1600 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1602 /* Check for password */
1603 ast_mutex_lock(&agentlock);
1606 if (!strcmp(p->agent, user) && !p->pending)
1607 strncpy(xpass, p->password, sizeof(xpass) - 1);
1610 ast_mutex_unlock(&agentlock);
1612 if (!ast_strlen_zero(xpass))
1613 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1617 errmsg = "agent-incorrect";
1620 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1623 /* Check again for accuracy */
1624 ast_mutex_lock(&agentlock);
1627 ast_mutex_lock(&p->lock);
1628 if (!strcmp(p->agent, user) &&
1629 !strcmp(p->password, pass) && !p->pending) {
1630 login_state = 1; /* Successful Login */
1631 /* Set Channel Specific Agent Overides */
1632 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1633 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1635 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1639 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1640 if (option_verbose > 2)
1641 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1643 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1644 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1645 if (p->autologoff < 0)
1647 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1648 if (option_verbose > 2)
1649 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1651 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1652 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1653 if (p->wrapuptime < 0)
1655 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1656 if (option_verbose > 2)
1657 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1659 /* End Channel Specific Agent Overides */
1661 char last_loginchan[80] = "";
1663 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1666 char tmpchan[AST_MAX_BUF] = "";
1668 /* Retrieve login chan */
1671 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1674 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1675 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1679 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1683 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);
1684 res = ast_streamfile(chan, "invalid", chan->language);
1686 res = ast_waitstream(chan, AST_DIGIT_ANY);
1699 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1700 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1702 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1703 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1705 if (ast_strlen_zero(p->loginchan)) {
1707 filename = "agent-loggedoff";
1709 p->acknowledged = 0;
1710 /* store/clear the global variable that stores agentid based on the callerid */
1711 if (chan->cid.cid_num) {
1712 char agentvar[AST_MAX_BUF];
1713 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1714 if (ast_strlen_zero(p->loginchan))
1715 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1717 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1719 if(update_cdr && chan->cdr)
1720 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1724 p->loginchan[0] = '\0';
1725 p->acknowledged = 0;
1727 ast_mutex_unlock(&p->lock);
1728 ast_mutex_unlock(&agentlock);
1729 if( !res && play_announcement==1 )
1730 res = ast_streamfile(chan, filename, chan->language);
1732 ast_waitstream(chan, "");
1733 ast_mutex_lock(&agentlock);
1734 ast_mutex_lock(&p->lock);
1736 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1738 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1741 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1743 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1745 /* Check once more just in case */
1748 if (callbackmode && !res) {
1749 /* Just say goodbye and be done with it */
1750 if (!ast_strlen_zero(p->loginchan)) {
1751 if (p->loginstart == 0)
1752 time(&p->loginstart);
1753 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1757 p->agent, p->loginchan, chan->uniqueid);
1758 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1759 if (option_verbose > 1)
1760 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1761 ast_device_state_changed("Agent/%s", p->agent);
1763 logintime = time(NULL) - p->loginstart;
1765 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1768 "Logintime: %ld\r\n"
1770 p->agent, last_loginchan, logintime, chan->uniqueid);
1771 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1772 if (option_verbose > 1)
1773 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1774 ast_device_state_changed("Agent/%s", p->agent);
1776 ast_mutex_unlock(&agentlock);
1778 res = ast_safe_sleep(chan, 500);
1779 ast_mutex_unlock(&p->lock);
1780 if (persistent_agents)
1783 #ifdef HONOR_MUSIC_CLASS
1784 /* check if the moh class was changed with setmusiconhold */
1785 if (*(chan->musicclass))
1786 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1788 ast_moh_start(chan, p->moh);
1789 if (p->loginstart == 0)
1790 time(&p->loginstart);
1791 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1795 p->agent, chan->name, chan->uniqueid);
1796 if (update_cdr && chan->cdr)
1797 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1798 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1799 if (option_verbose > 1)
1800 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1801 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1802 /* Login this channel and wait for it to
1808 check_availability(p, 0);
1809 ast_mutex_unlock(&p->lock);
1810 ast_mutex_unlock(&agentlock);
1811 ast_device_state_changed("Agent/%s", p->agent);
1813 ast_mutex_lock(&p->lock);
1814 if (p->chan != chan)
1816 ast_mutex_unlock(&p->lock);
1817 /* Yield here so other interested threads can kick in. */
1822 ast_mutex_lock(&agentlock);
1823 ast_mutex_lock(&p->lock);
1824 if (p->lastdisc.tv_sec) {
1825 gettimeofday(&tv, NULL);
1826 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1827 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1829 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1830 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1834 check_availability(p, 0);
1837 ast_mutex_unlock(&p->lock);
1838 ast_mutex_unlock(&agentlock);
1839 /* Synchronize channel ownership between call to agent and itself. */
1840 ast_mutex_lock( &p->app_lock );
1841 ast_mutex_lock(&p->lock);
1842 p->owning_app = pthread_self();
1843 ast_mutex_unlock(&p->lock);
1845 res = agent_ack_sleep(p);
1847 res = ast_safe_sleep_conditional( chan, 1000,
1848 agent_cont_sleep, p );
1849 ast_mutex_unlock( &p->app_lock );
1850 if ((p->ackcall > 1) && (res == 1)) {
1851 ast_mutex_lock(&agentlock);
1852 ast_mutex_lock(&p->lock);
1853 check_availability(p, 0);
1854 ast_mutex_unlock(&p->lock);
1855 ast_mutex_unlock(&agentlock);
1860 ast_mutex_lock(&p->lock);
1861 if (res && p->owner)
1862 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1863 /* Log us off if appropriate */
1864 if (p->chan == chan)
1866 p->acknowledged = 0;
1867 logintime = time(NULL) - p->loginstart;
1869 ast_mutex_unlock(&p->lock);
1870 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1872 "Logintime: %ld\r\n"
1874 p->agent, logintime, chan->uniqueid);
1875 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1876 if (option_verbose > 1)
1877 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1878 /* If there is no owner, go ahead and kill it now */
1879 ast_device_state_changed("Agent/%s", p->agent);
1880 if (p->dead && !p->owner) {
1881 ast_mutex_destroy(&p->lock);
1882 ast_mutex_destroy(&p->app_lock);
1887 ast_mutex_unlock(&p->lock);
1892 ast_mutex_unlock(&p->lock);
1893 errmsg = "agent-alreadyon";
1898 ast_mutex_unlock(&p->lock);
1902 ast_mutex_unlock(&agentlock);
1904 if (!res && (max_login_tries==0 || tries < max_login_tries))
1905 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1908 LOCAL_USER_REMOVE(u);
1910 res = ast_safe_sleep(chan, 500);
1912 /* AgentLogin() exit */
1913 if (!callbackmode) {
1916 /* AgentCallbackLogin() exit*/
1919 if (login_state > 0) {
1920 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1921 if (login_state==1) {
1922 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1923 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1926 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1930 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1932 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1934 /* Do we need to play agent-goodbye now that we will be hanging up? */
1935 if (play_announcement==1) {
1937 res = ast_safe_sleep(chan, 1000);
1938 res = ast_streamfile(chan, agent_goodbye, chan->language);
1940 res = ast_waitstream(chan, "");
1942 res = ast_safe_sleep(chan, 1000);
1945 /* We should never get here if next priority exists when in callbackmode */
1949 static int login_exec(struct ast_channel *chan, void *data)
1951 return __login_exec(chan, data, 0);
1954 static int callback_exec(struct ast_channel *chan, void *data)
1956 return __login_exec(chan, data, 1);
1959 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1961 int exitifnoagentid = 0;
1963 int changeoutgoing = 0;
1965 char agent[AST_MAX_AGENT], *tmp;
1968 if (strchr(data, 'd'))
1969 exitifnoagentid = 1;
1970 if (strchr(data, 'n'))
1972 if (strchr(data, 'c'))
1975 if (chan->cid.cid_num) {
1976 char agentvar[AST_MAX_BUF];
1977 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1978 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1979 struct agent_pvt *p = agents;
1980 strncpy(agent, tmp, sizeof(agent) - 1);
1981 ast_mutex_lock(&agentlock);
1983 if (!strcasecmp(p->agent, tmp)) {
1984 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1985 __agent_start_monitoring(chan, p, 1);
1990 ast_mutex_unlock(&agentlock);
1995 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);
2000 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");
2002 /* check if there is n + 101 priority */
2004 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2005 chan->priority+=100;
2006 if (option_verbose > 2)
2007 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2009 else if (exitifnoagentid)
2015 /* Dump AgentCallbackLogin agents to the database for persistence
2018 static void dump_agents(void)
2020 struct agent_pvt *cur_agent = NULL;
2022 for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2023 if (cur_agent->chan)
2026 if (!ast_strlen_zero(cur_agent->loginchan)) {
2027 if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan))
2028 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2029 else if (option_debug)
2030 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2032 /* Delete - no agent or there is an error */
2033 ast_db_del(pa_family, cur_agent->agent);
2038 /* Reload the persistent agents from astdb */
2039 static void reload_agents(void)
2042 struct ast_db_entry *db_tree;
2043 struct ast_db_entry *entry;
2044 struct agent_pvt *cur_agent;
2045 char agent_data[80];
2047 db_tree = ast_db_gettree(pa_family, NULL);
2049 ast_mutex_lock(&agentlock);
2050 for (entry = db_tree; entry; entry = entry->next) {
2051 agent_num = entry->key + strlen(pa_family) + 2;
2054 ast_mutex_lock(&cur_agent->lock);
2055 if (strcmp(agent_num, cur_agent->agent) == 0)
2057 ast_mutex_unlock(&cur_agent->lock);
2058 cur_agent = cur_agent->next;
2061 ast_db_del(pa_family, agent_num);
2064 ast_mutex_unlock(&cur_agent->lock);
2065 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2067 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2068 strncpy(cur_agent->loginchan, agent_data, sizeof(cur_agent->loginchan)-1);
2069 if (cur_agent->loginstart == 0)
2070 time(&cur_agent->loginstart);
2071 ast_device_state_changed("Agent/%s", cur_agent->agent);
2074 ast_mutex_unlock(&agentlock);
2076 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2077 ast_db_freetree(db_tree);
2082 /*--- agent_devicestate: Part of PBX channel interface ---*/
2083 static int agent_devicestate(void *data)
2085 struct agent_pvt *p;
2087 ast_group_t groupmatch;
2090 int res = AST_DEVICE_INVALID;
2093 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2094 groupmatch = (1 << groupoff);
2095 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2096 groupmatch = (1 << groupoff);
2102 /* Check actual logged in agents first */
2103 ast_mutex_lock(&agentlock);
2106 ast_mutex_lock(&p->lock);
2107 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2109 if (res != AST_DEVICE_INUSE)
2110 res = AST_DEVICE_BUSY;
2112 if (res == AST_DEVICE_BUSY)
2113 res = AST_DEVICE_INUSE;
2114 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2115 if (res == AST_DEVICE_INVALID)
2116 res = AST_DEVICE_UNKNOWN;
2117 } else if (res == AST_DEVICE_INVALID)
2118 res = AST_DEVICE_UNAVAILABLE;
2120 if (!strcmp(data, p->agent)) {
2121 ast_mutex_unlock(&p->lock);
2125 ast_mutex_unlock(&p->lock);
2128 ast_mutex_unlock(&agentlock);
2132 /*--- load_module: Initialize channel module ---*/
2135 /* Make sure we can register our agent channel type */
2136 if (ast_channel_register(&agent_tech)) {
2137 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2140 /* Dialplan applications */
2141 ast_register_application(app, login_exec, synopsis, descrip);
2142 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2143 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2144 /* Manager command */
2145 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2146 /* CLI Application */
2147 ast_cli_register(&cli_show_agents);
2148 ast_cli_register(&cli_agent_logoff);
2149 /* Read in the config */
2150 read_agent_config();
2151 if (persistent_agents)
2158 read_agent_config();
2159 if (persistent_agents)
2166 struct agent_pvt *p;
2167 /* First, take us out of the channel loop */
2168 /* Unregister CLI application */
2169 ast_cli_unregister(&cli_show_agents);
2170 ast_cli_unregister(&cli_agent_logoff);
2171 /* Unregister dialplan applications */
2172 ast_unregister_application(app);
2173 ast_unregister_application(app2);
2174 ast_unregister_application(app3);
2175 /* Unregister manager command */
2176 ast_manager_unregister("Agents");
2177 /* Unregister channel */
2178 ast_channel_unregister(&agent_tech);
2179 if (!ast_mutex_lock(&agentlock)) {
2180 /* Hangup all interfaces if they have an owner */
2184 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2188 ast_mutex_unlock(&agentlock);
2190 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2199 ast_mutex_lock(&usecnt_lock);
2201 ast_mutex_unlock(&usecnt_lock);
2207 return ASTERISK_GPL_KEY;
2212 return (char *) desc;