2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Agents
6 * Copyright (C) 1999 - 2005, Digium Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
16 #include <asterisk/lock.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/channel_pvt.h>
19 #include <asterisk/config.h>
20 #include <asterisk/logger.h>
21 #include <asterisk/module.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/options.h>
24 #include <asterisk/lock.h>
25 #include <asterisk/sched.h>
26 #include <asterisk/io.h>
27 #include <asterisk/rtp.h>
28 #include <asterisk/acl.h>
29 #include <asterisk/callerid.h>
30 #include <asterisk/file.h>
31 #include <asterisk/cli.h>
32 #include <asterisk/app.h>
33 #include <asterisk/musiconhold.h>
34 #include <asterisk/manager.h>
35 #include <asterisk/features.h>
36 #include <asterisk/utils.h>
37 #include <asterisk/causes.h>
38 #include <asterisk/astdb.h>
39 #include <sys/socket.h>
45 #include <arpa/inet.h>
46 #include <sys/signal.h>
48 static char *desc = "Agent Proxy Channel";
49 static char *channeltype = "Agent";
50 static char *tdesc = "Call Agent Proxy Channel";
51 static char *config = "agents.conf";
53 static char *app = "AgentLogin";
54 static char *app2 = "AgentCallbackLogin";
55 static char *app3 = "AgentMonitorOutgoing";
57 static char *synopsis = "Call agent login";
58 static char *synopsis2 = "Call agent callback login";
59 static char *synopsis3 = "Record agent's outgoing call";
61 static char *descrip =
62 " AgentLogin([AgentNo][|options]):\n"
63 "Asks the agent to login to the system. Always returns -1. While\n"
64 "logged in, the agent can receive calls and will hear a 'beep'\n"
65 "when a new call comes in. The agent can dump the call by pressing\n"
67 "The option string may contain zero or more of the following characters:\n"
68 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
70 static char *descrip2 =
71 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
72 "Asks the agent to login to the system with callback.\n"
73 "The agent's callback extension is called (optionally with the specified\n"
75 "The option string may contain zero or more of the following characters:\n"
76 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
80 static char *descrip3 =
81 " AgentMonitorOutgoing([options]):\n"
82 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
83 "comparision of the callerid of the current interface and the global variable \n"
84 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
85 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
86 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
88 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
89 "the agentid are not specified it'll look for n+101 priority.\n"
91 " 'd' - make the app return -1 if there is an error condition and there is\n"
92 " no extension n+101\n"
93 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
94 " 'n' - don't generate the warnings when there is no callerid or the\n"
95 " agentid is not known.\n"
96 " It's handy if you want to have one context for agent and non-agent calls.\n";
98 static char mandescr_agents[] =
99 "Description: Will list info about all possible agents.\n"
102 static char moh[80] = "default";
104 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
105 #define AST_MAX_BUF 256
106 #define AST_MAX_FILENAME_LEN 256
108 /* Persistent Agents astdb family */
109 static const char *pa_family = "/Agents";
110 /* The maximum lengh of each persistent member agent database entry */
111 #define PA_MAX_LEN 2048
112 /* queues.conf [general] option */
113 static int persistent_agents = 0;
114 static void dump_agents(void);
116 static int capability = -1;
118 static ast_group_t group;
119 static int autologoff;
120 static int wrapuptime;
123 static int maxlogintries = 3;
124 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
126 static int usecnt =0;
127 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
129 /* Protect the interface list (of pvt's) */
130 AST_MUTEX_DEFINE_STATIC(agentlock);
132 static int recordagentcalls = 0;
133 static char recordformat[AST_MAX_BUF] = "";
134 static char recordformatext[AST_MAX_BUF] = "";
135 static int createlink = 0;
136 static char urlprefix[AST_MAX_BUF] = "";
137 static char savecallsin[AST_MAX_BUF] = "";
138 static int updatecdr = 0;
139 static char beep[AST_MAX_BUF] = "beep";
141 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
143 static struct agent_pvt {
144 ast_mutex_t lock; /* Channel private lock */
145 int dead; /* Poised for destruction? */
146 int pending; /* Not a real agent -- just pending a match */
147 int abouttograb; /* About to grab */
148 int autologoff; /* Auto timeout time */
149 int ackcall; /* ackcall */
150 time_t loginstart; /* When agent first logged in (0 when logged off) */
151 time_t start; /* When call started */
152 struct timeval lastdisc; /* When last disconnected */
153 int wrapuptime; /* Wrapup time in ms */
154 ast_group_t group; /* Group memberships */
155 int acknowledged; /* Acknowledged */
156 char moh[80]; /* Which music on hold */
157 char agent[AST_MAX_AGENT]; /* Agent ID */
158 char password[AST_MAX_AGENT]; /* Password for Agent login */
159 char name[AST_MAX_AGENT];
160 ast_mutex_t app_lock; /* Synchronization between owning applications */
161 volatile pthread_t owning_app; /* Owning application thread id */
162 volatile int app_sleep_cond; /* Sleep condition for the login app */
163 struct ast_channel *owner; /* Agent */
165 struct ast_channel *chan; /* Channel we use */
166 struct agent_pvt *next; /* Agent */
169 #define CHECK_FORMATS(ast, p) do { \
171 if (ast->nativeformats != p->chan->nativeformats) { \
172 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
173 /* Native formats changed, reset things */ \
174 ast->nativeformats = p->chan->nativeformats; \
175 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
176 ast_set_read_format(ast, ast->readformat); \
177 ast_set_write_format(ast, ast->writeformat); \
179 if (p->chan->readformat != ast->pvt->rawreadformat) \
180 ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
181 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
182 ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
186 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
187 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
188 totally impractical combinations XXX */
190 #define CLEANUP(ast, p) do { \
193 for (x=0;x<AST_MAX_FDS;x++) {\
194 if (x != AST_MAX_FDS - 2) \
195 ast->fds[x] = p->chan->fds[x]; \
197 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
203 static void agent_unlink(struct agent_pvt *agent)
205 struct agent_pvt *p, *prev;
211 prev->next = agent->next;
213 agents = agent->next;
221 static struct agent_pvt *add_agent(char *agent, int pending)
223 char tmp[AST_MAX_BUF] = "";
224 char *password=NULL, *name=NULL;
225 struct agent_pvt *p, *prev;
227 strncpy(tmp, agent, sizeof(tmp) - 1);
228 if ((password = strchr(tmp, ','))) {
231 while (*password < 33) password++;
233 if (password && (name = strchr(password, ','))) {
236 while (*name < 33) name++;
241 if (!pending && !strcmp(p->agent, tmp))
247 p = malloc(sizeof(struct agent_pvt));
249 memset(p, 0, sizeof(struct agent_pvt));
250 strncpy(p->agent, tmp, sizeof(p->agent) -1);
251 ast_mutex_init(&p->lock);
252 ast_mutex_init(&p->app_lock);
253 p->owning_app = (pthread_t) -1;
254 p->app_sleep_cond = 1;
256 p->pending = pending;
267 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
268 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
269 strncpy(p->moh, moh, sizeof(p->moh) - 1);
270 p->ackcall = ackcall;
271 p->autologoff = autologoff;
272 p->wrapuptime = wrapuptime;
280 static int agent_cleanup(struct agent_pvt *p)
282 struct ast_channel *chan = p->owner;
284 chan->pvt->pvt = NULL;
285 p->app_sleep_cond = 1;
286 /* Release ownership of the agent to other threads (presumably running the login app). */
287 ast_mutex_unlock(&p->app_lock);
289 ast_channel_free(chan);
291 ast_mutex_destroy(&p->lock);
292 ast_mutex_destroy(&p->app_lock);
298 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
300 static int agent_answer(struct ast_channel *ast)
302 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
306 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
308 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
309 char filename[AST_MAX_BUF];
314 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
315 /* substitute . for - */
316 if ((pointer = strchr(filename, '.')))
318 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
319 ast_monitor_start(ast, recordformat, tmp, needlock);
320 ast_monitor_setjoinfiles(ast, 1);
321 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
323 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
326 ast->cdr = ast_cdr_alloc();
327 ast_cdr_setuserfield(ast, tmp2);
330 ast_log(LOG_ERROR, "Recording already started on that call.\n");
334 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
336 return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
339 static struct ast_frame *agent_read(struct ast_channel *ast)
341 struct agent_pvt *p = ast->pvt->pvt;
342 struct ast_frame *f = NULL;
343 static struct ast_frame null_frame = { AST_FRAME_NULL, };
344 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
345 ast_mutex_lock(&p->lock);
346 CHECK_FORMATS(ast, p);
348 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
349 if (ast->fdno == AST_MAX_FDS - 3)
350 p->chan->fdno = AST_MAX_FDS - 2;
352 p->chan->fdno = ast->fdno;
353 f = ast_read(p->chan);
357 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
359 /* Note that we don't hangup if it's not a callback because Asterisk will do it
360 for us when the PBX instance that called login finishes */
361 if (!ast_strlen_zero(p->loginchan)) {
362 p->chan->_bridge = NULL;
364 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
367 gettimeofday(&p->lastdisc, NULL);
368 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
369 if (p->lastdisc.tv_usec > 1000000) {
370 p->lastdisc.tv_usec -= 1000000;
371 p->lastdisc.tv_sec++;
373 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
380 if (p->chan && f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
382 ast_log(LOG_DEBUG, "Got answer on %s\n", p->chan->name);
384 if (option_verbose > 2)
385 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
386 /* Don't pass answer along */
395 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
396 if (!p->acknowledged) {
397 if (option_verbose > 2)
398 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
404 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
405 /* * terminates call */
410 if (p->chan && !p->chan->_bridge) {
411 if (strcasecmp(p->chan->type, "Local")) {
412 p->chan->_bridge = ast;
414 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
417 ast_mutex_unlock(&p->lock);
418 if (recordagentcalls && f == &answer_frame)
419 agent_start_monitoring(ast,0);
423 static int agent_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen)
425 struct agent_pvt *p = ast->pvt->pvt;
427 ast_mutex_lock(&p->lock);
429 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
430 ast_mutex_unlock(&p->lock);
434 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
436 struct agent_pvt *p = ast->pvt->pvt;
438 CHECK_FORMATS(ast, p);
439 ast_mutex_lock(&p->lock);
441 if ((f->frametype != AST_FRAME_VOICE) ||
442 (f->subclass == p->chan->writeformat)) {
443 res = ast_write(p->chan, f);
445 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
451 ast_mutex_unlock(&p->lock);
455 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
457 struct agent_pvt *p = newchan->pvt->pvt;
458 ast_mutex_lock(&p->lock);
459 if (p->owner != oldchan) {
460 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
461 ast_mutex_unlock(&p->lock);
465 ast_mutex_unlock(&p->lock);
469 static int agent_indicate(struct ast_channel *ast, int condition)
471 struct agent_pvt *p = ast->pvt->pvt;
473 ast_mutex_lock(&p->lock);
475 res = ast_indicate(p->chan, condition);
478 ast_mutex_unlock(&p->lock);
482 static int agent_digit(struct ast_channel *ast, char digit)
484 struct agent_pvt *p = ast->pvt->pvt;
486 ast_mutex_lock(&p->lock);
488 res = p->chan->pvt->send_digit(p->chan, digit);
491 ast_mutex_unlock(&p->lock);
495 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
497 struct agent_pvt *p = ast->pvt->pvt;
500 ast_mutex_lock(&p->lock);
504 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
505 newstate = AST_STATE_DIALING;
508 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
511 ast_mutex_unlock(&p->lock);
513 ast_setstate(ast, newstate);
515 } else if (!ast_strlen_zero(p->loginchan)) {
517 /* Call on this agent */
518 if (option_verbose > 2)
519 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
520 if (p->chan->cid.cid_num)
521 free(p->chan->cid.cid_num);
522 if (ast->cid.cid_num)
523 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
525 p->chan->cid.cid_num = NULL;
526 if (p->chan->cid.cid_name)
527 free(p->chan->cid.cid_name);
528 if (ast->cid.cid_name)
529 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
531 p->chan->cid.cid_name = NULL;
532 ast_channel_inherit_variables(ast, p->chan);
533 res = ast_call(p->chan, p->loginchan, 0);
535 ast_mutex_unlock(&p->lock);
538 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
539 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
540 res = ast_streamfile(p->chan, beep, p->chan->language);
541 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
543 res = ast_waitstream(p->chan, "");
544 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
547 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
548 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
550 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
557 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
558 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
560 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
564 /* Call is immediately up, or might need ack */
566 newstate = AST_STATE_RINGING;
568 newstate = AST_STATE_UP;
569 if (recordagentcalls)
570 agent_start_monitoring(ast,0);
576 ast_mutex_unlock(&p->lock);
578 ast_setstate(ast, newstate);
582 static int agent_hangup(struct ast_channel *ast)
584 struct agent_pvt *p = ast->pvt->pvt;
586 ast_mutex_lock(&p->lock);
588 ast->pvt->pvt = NULL;
589 p->app_sleep_cond = 1;
592 /* if they really are hung up then set start to 0 so the test
593 * later if we're called on an already downed channel
594 * doesn't cause an agent to be logged out like when
595 * agent_request() is followed immediately by agent_hangup()
596 * as in apps/app_chanisavail.c:chanavail_exec()
599 ast_mutex_lock(&usecnt_lock);
601 ast_mutex_unlock(&usecnt_lock);
603 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
604 if (p->start && (ast->_state != AST_STATE_UP)) {
605 howlong = time(NULL) - p->start;
607 } else if (ast->_state == AST_STATE_RESERVED) {
612 /* If they're dead, go ahead and hang up on the agent now */
613 if (!ast_strlen_zero(p->loginchan)) {
614 /* Store last disconnect time */
616 gettimeofday(&p->lastdisc, NULL);
617 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
618 if (p->lastdisc.tv_usec >= 1000000) {
619 p->lastdisc.tv_usec -= 1000000;
620 p->lastdisc.tv_sec++;
622 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
624 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
626 /* Recognize the hangup and pass it along immediately */
630 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
631 if (howlong && p->autologoff && (howlong > p->autologoff)) {
632 char agent[AST_MAX_AGENT] = "";
633 long logintime = time(NULL) - p->loginstart;
635 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
636 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
640 "Reason: Autologoff\r\n"
642 p->agent, p->loginchan, logintime, ast->uniqueid);
643 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
644 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
645 p->loginchan[0] = '\0';
646 ast_device_state_changed("Agent/%s", p->agent);
648 } else if (p->dead) {
649 ast_mutex_lock(&p->chan->lock);
650 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
651 ast_mutex_unlock(&p->chan->lock);
653 ast_mutex_lock(&p->chan->lock);
654 ast_moh_start(p->chan, p->moh);
655 ast_mutex_unlock(&p->chan->lock);
659 ast_mutex_unlock(&p->lock);
660 /* Release ownership of the agent to other threads (presumably running the login app). */
661 ast_mutex_unlock(&p->app_lock);
662 } else if (p->dead) {
663 /* Go ahead and lose it */
664 ast_mutex_unlock(&p->lock);
665 /* Release ownership of the agent to other threads (presumably running the login app). */
666 ast_mutex_unlock(&p->app_lock);
668 ast_mutex_unlock(&p->lock);
669 /* Release ownership of the agent to other threads (presumably running the login app). */
670 ast_mutex_unlock(&p->app_lock);
673 ast_mutex_unlock(&p->lock);
676 ast_mutex_lock(&agentlock);
678 ast_mutex_unlock(&agentlock);
680 if (p->abouttograb) {
681 /* Let the "about to grab" thread know this isn't valid anymore, and let it
684 } else if (p->dead) {
685 ast_mutex_destroy(&p->lock);
686 ast_mutex_destroy(&p->app_lock);
690 /* Not dead -- check availability now */
691 ast_mutex_lock(&p->lock);
692 /* Store last disconnect time */
693 gettimeofday(&p->lastdisc, NULL);
694 ast_mutex_unlock(&p->lock);
696 /* Release ownership of the agent to other threads (presumably running the login app). */
697 ast_mutex_unlock(&p->app_lock);
702 static int agent_cont_sleep( void *data )
708 p = (struct agent_pvt *)data;
710 ast_mutex_lock(&p->lock);
711 res = p->app_sleep_cond;
712 if (p->lastdisc.tv_sec) {
713 gettimeofday(&tv, NULL);
714 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
715 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
718 ast_mutex_unlock(&p->lock);
721 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
726 static int agent_ack_sleep( void *data )
733 /* Wait a second and look for something */
735 p = (struct agent_pvt *)data;
738 to = ast_waitfor(p->chan, to);
747 f = ast_read(p->chan);
752 if (f->frametype == AST_FRAME_DTMF)
757 ast_mutex_lock(&p->lock);
758 if (!p->app_sleep_cond) {
759 ast_mutex_unlock(&p->lock);
762 } else if (res == '#') {
763 ast_mutex_unlock(&p->lock);
767 ast_mutex_unlock(&p->lock);
775 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
778 struct ast_channel *ret=NULL;
781 p = bridge->pvt->pvt;
783 ret = bridge->_bridge;
784 else if (chan == bridge->_bridge)
787 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
791 /*--- agent_new: Create new agent channel ---*/
792 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
794 struct ast_channel *tmp;
795 struct ast_frame null_frame = { AST_FRAME_NULL };
798 ast_log(LOG_WARNING, "No channel? :(\n");
802 tmp = ast_channel_alloc(0);
805 tmp->nativeformats = p->chan->nativeformats;
806 tmp->writeformat = p->chan->writeformat;
807 tmp->pvt->rawwriteformat = p->chan->writeformat;
808 tmp->readformat = p->chan->readformat;
809 tmp->pvt->rawreadformat = p->chan->readformat;
810 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
811 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
812 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
814 tmp->nativeformats = AST_FORMAT_SLINEAR;
815 tmp->writeformat = AST_FORMAT_SLINEAR;
816 tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
817 tmp->readformat = AST_FORMAT_SLINEAR;
818 tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
821 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
823 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
824 tmp->type = channeltype;
825 /* Safe, agentlock already held */
826 ast_setstate(tmp, state);
828 tmp->pvt->send_digit = agent_digit;
829 tmp->pvt->call = agent_call;
830 tmp->pvt->hangup = agent_hangup;
831 tmp->pvt->answer = agent_answer;
832 tmp->pvt->read = agent_read;
833 tmp->pvt->write = agent_write;
834 tmp->pvt->send_html = agent_sendhtml;
835 tmp->pvt->exception = agent_read;
836 tmp->pvt->indicate = agent_indicate;
837 tmp->pvt->fixup = agent_fixup;
838 tmp->pvt->bridged_channel = agent_bridgedchannel;
840 ast_mutex_lock(&usecnt_lock);
842 ast_mutex_unlock(&usecnt_lock);
843 ast_update_use_count();
845 /* Wake up and wait for other applications (by definition the login app)
846 * to release this channel). Takes ownership of the agent channel
847 * to this thread only.
848 * For signalling the other thread, ast_queue_frame is used until we
849 * can safely use signals for this purpose. The pselect() needs to be
850 * implemented in the kernel for this.
852 p->app_sleep_cond = 0;
853 if( ast_mutex_trylock(&p->app_lock) )
856 ast_queue_frame(p->chan, &null_frame);
857 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
858 ast_mutex_lock(&p->app_lock);
859 ast_mutex_lock(&p->lock);
863 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
865 tmp->pvt->pvt = NULL;
866 p->app_sleep_cond = 1;
867 ast_channel_free( tmp );
868 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
869 ast_mutex_unlock(&p->app_lock);
873 p->owning_app = pthread_self();
874 /* After the above step, there should not be any blockers. */
876 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
877 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
880 ast_moh_stop(p->chan);
883 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
888 /*--- read_agent_config: Read configuration data (agents.conf) ---*/
889 static int read_agent_config(void)
891 struct ast_config *cfg;
892 struct ast_variable *v;
893 struct agent_pvt *p, *pl, *pn;
900 cfg = ast_config_load(config);
902 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
905 ast_mutex_lock(&agentlock);
911 strncpy(moh, "default", sizeof(moh) - 1);
912 /* set the default recording values */
913 recordagentcalls = 0;
915 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
916 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
918 savecallsin[0] = '\0';
920 /* Read in [general] section for persistance */
921 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
922 persistent_agents = ast_true(general_val);
924 /* Read in the [agents] section */
925 v = ast_variable_browse(cfg, "agents");
927 /* Create the interface list */
928 if (!strcasecmp(v->name, "agent")) {
929 add_agent(v->value, 0);
930 } else if (!strcasecmp(v->name, "group")) {
931 group = ast_get_group(v->value);
932 } else if (!strcasecmp(v->name, "autologoff")) {
933 autologoff = atoi(v->value);
936 } else if (!strcasecmp(v->name, "ackcall")) {
937 if (!strcasecmp(v->value, "always"))
939 else if (ast_true(v->value))
943 } else if (!strcasecmp(v->name, "wrapuptime")) {
944 wrapuptime = atoi(v->value);
947 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
948 maxlogintries = atoi(v->value);
949 if (maxlogintries < 0)
951 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
952 strcpy(agentgoodbye,v->value);
953 } else if (!strcasecmp(v->name, "musiconhold")) {
954 strncpy(moh, v->value, sizeof(moh) - 1);
955 } else if (!strcasecmp(v->name, "updatecdr")) {
956 if (ast_true(v->value))
960 } else if (!strcasecmp(v->name, "recordagentcalls")) {
961 recordagentcalls = ast_true(v->value);
962 } else if (!strcasecmp(v->name, "createlink")) {
963 createlink = ast_true(v->value);
964 } else if (!strcasecmp(v->name, "recordformat")) {
965 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
966 if (!strcasecmp(v->value, "wav49"))
967 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
969 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
970 } else if (!strcasecmp(v->name, "urlprefix")) {
971 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
972 if (urlprefix[strlen(urlprefix) - 1] != '/')
973 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
974 } else if (!strcasecmp(v->name, "savecallsin")) {
975 if (v->value[0] == '/')
976 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
978 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
979 if (savecallsin[strlen(savecallsin) - 1] != '/')
980 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
981 } else if (!strcasecmp(v->name, "custom_beep")) {
982 strncpy(beep, v->value, sizeof(beep) - 1);
996 /* Destroy if appropriate */
999 ast_mutex_destroy(&p->lock);
1000 ast_mutex_destroy(&p->app_lock);
1003 /* Cause them to hang up */
1004 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1011 ast_mutex_unlock(&agentlock);
1012 ast_config_destroy(cfg);
1016 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1018 struct ast_channel *chan=NULL, *parent=NULL;
1019 struct agent_pvt *p;
1023 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1025 ast_mutex_lock(&agentlock);
1028 if (p == newlyavailable) {
1032 ast_mutex_lock(&p->lock);
1033 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1035 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1036 /* We found a pending call, time to merge */
1037 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1040 ast_mutex_unlock(&p->lock);
1043 ast_mutex_unlock(&p->lock);
1047 ast_mutex_unlock(&agentlock);
1048 if (parent && chan) {
1049 if (newlyavailable->ackcall > 1) {
1050 /* Don't do beep here */
1053 if (option_debug > 2)
1054 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1055 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1056 if (option_debug > 2)
1057 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1059 res = ast_waitstream(newlyavailable->chan, "");
1060 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1064 /* Note -- parent may have disappeared */
1065 if (p->abouttograb) {
1066 newlyavailable->acknowledged = 1;
1067 /* Safe -- agent lock already held */
1068 ast_setstate(parent, AST_STATE_UP);
1069 ast_setstate(chan, AST_STATE_UP);
1070 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1071 /* Go ahead and mark the channel as a zombie so that masquerade will
1072 destroy it for us, and we need not call ast_hangup */
1073 ast_mutex_lock(&parent->lock);
1074 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1075 ast_channel_masquerade(parent, chan);
1076 ast_mutex_unlock(&parent->lock);
1080 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1081 agent_cleanup(newlyavailable);
1085 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1086 agent_cleanup(newlyavailable);
1092 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1094 struct agent_pvt *p;
1097 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1099 ast_mutex_lock(&agentlock);
1102 if (p == newlyavailable) {
1106 ast_mutex_lock(&p->lock);
1107 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1109 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1110 ast_mutex_unlock(&p->lock);
1113 ast_mutex_unlock(&p->lock);
1117 ast_mutex_unlock(&agentlock);
1119 ast_mutex_unlock(&newlyavailable->lock);
1120 if (option_debug > 2)
1121 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1122 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1123 if (option_debug > 2)
1124 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1126 res = ast_waitstream(newlyavailable->chan, "");
1128 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1130 ast_mutex_lock(&newlyavailable->lock);
1135 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1136 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1138 struct agent_pvt *p;
1139 struct ast_channel *chan = NULL;
1141 ast_group_t groupmatch;
1148 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1149 groupmatch = (1 << groupoff);
1150 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1151 groupmatch = (1 << groupoff);
1157 /* Check actual logged in agents first */
1158 ast_mutex_lock(&agentlock);
1161 ast_mutex_lock(&p->lock);
1162 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1163 ast_strlen_zero(p->loginchan)) {
1166 if (!p->lastdisc.tv_sec) {
1167 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1168 if (!p->owner && p->chan) {
1170 chan = agent_new(p, AST_STATE_DOWN);
1173 ast_mutex_unlock(&p->lock);
1178 ast_mutex_unlock(&p->lock);
1184 ast_mutex_lock(&p->lock);
1185 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1186 if (p->chan || !ast_strlen_zero(p->loginchan))
1188 gettimeofday(&tv, NULL);
1190 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1192 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1193 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1194 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1195 if (!p->owner && p->chan) {
1196 /* Could still get a fixed agent */
1197 chan = agent_new(p, AST_STATE_DOWN);
1198 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1199 /* Adjustable agent */
1200 p->chan = ast_request("Local", format, p->loginchan, cause);
1202 chan = agent_new(p, AST_STATE_DOWN);
1205 ast_mutex_unlock(&p->lock);
1210 ast_mutex_unlock(&p->lock);
1215 if (!chan && waitforagent) {
1216 /* No agent available -- but we're requesting to wait for one.
1217 Allocate a place holder */
1220 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1221 p = add_agent(data, 1);
1222 p->group = groupmatch;
1223 chan = agent_new(p, AST_STATE_DOWN);
1225 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1228 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1231 *cause = AST_CAUSE_BUSY;
1233 *cause = AST_CAUSE_UNREGISTERED;
1234 ast_mutex_unlock(&agentlock);
1238 static int powerof(unsigned int v)
1241 for (x=0;x<32;x++) {
1242 if (v & (1 << x)) return x;
1247 static int action_agents(struct mansession *s, struct message *m)
1249 struct agent_pvt *p;
1250 char *username = NULL;
1251 char *loginChan = NULL;
1252 char *talkingtoChan = NULL;
1253 char *status = NULL;
1255 ast_mutex_lock(&agentlock);
1258 ast_mutex_lock(&p->lock);
1261 AGENT_LOGGEDOFF - Agent isn't logged in
1262 AGENT_IDLE - Agent is logged in, and waiting for call
1263 AGENT_ONCALL - Agent is logged in, and on a call
1264 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1266 if(!ast_strlen_zero(p->name)) {
1272 /* Set a default status. It 'should' get changed. */
1273 status = "AGENT_UNKNOWN";
1276 loginChan = p->loginchan;
1277 if(p->owner && p->owner->_bridge) {
1278 talkingtoChan = p->chan->cid.cid_num;
1279 status = "AGENT_ONCALL";
1281 talkingtoChan = "n/a";
1282 status = "AGENT_IDLE";
1284 } else if(!ast_strlen_zero(p->loginchan)) {
1285 loginChan = p->loginchan;
1286 talkingtoChan = "n/a";
1287 status = "AGENT_IDLE";
1288 if(p->acknowledged) {
1289 sprintf(loginChan, " %s (Confirmed)", loginChan);
1293 talkingtoChan = "n/a";
1294 status = "AGENT_LOGGEDOFF";
1297 ast_cli(s->fd, "Event: Agents\r\n"
1301 "LoggedInChan: %s\r\n"
1302 "LoggedInTime: %ld\r\n"
1305 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1306 ast_mutex_unlock(&p->lock);
1309 ast_mutex_unlock(&agentlock);
1313 static int agent_logoff_cmd(int fd, int argc, char **argv)
1315 struct agent_pvt *p;
1316 char *agent = argv[2] + 6;
1319 if (argc < 3 || argc > 4)
1320 return RESULT_SHOWUSAGE;
1321 if (argc == 4 && strcasecmp(argv[3], "soft"))
1322 return RESULT_SHOWUSAGE;
1324 for (p=agents; p; p=p->next) {
1325 if (!strcasecmp(p->agent, agent)) {
1328 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1331 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1334 logintime = time(NULL) - p->loginstart;
1337 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1340 "Logintime: %ld\r\n",
1341 p->agent, p->loginchan, logintime);
1342 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1343 p->loginchan[0] = '\0';
1344 ast_cli(fd, "Logging out %s\n", agent);
1348 return RESULT_SUCCESS;
1351 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1353 struct agent_pvt *p;
1354 char name[AST_MAX_AGENT];
1358 for (p=agents; p; p=p->next) {
1359 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1360 if (!strncasecmp(word, name, strlen(word))) {
1361 if (++which > state) {
1362 return strdup(name);
1366 } else if (pos == 3 && state == 0) {
1367 return strdup("soft");
1372 /*--- agents_show: Show agents in cli ---*/
1373 static int agents_show(int fd, int argc, char **argv)
1375 struct agent_pvt *p;
1376 char username[AST_MAX_BUF];
1377 char location[AST_MAX_BUF] = "";
1378 char talkingto[AST_MAX_BUF] = "";
1379 char moh[AST_MAX_BUF];
1382 return RESULT_SHOWUSAGE;
1383 ast_mutex_lock(&agentlock);
1386 ast_mutex_lock(&p->lock);
1389 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1391 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1393 if (!ast_strlen_zero(p->name))
1394 snprintf(username, sizeof(username), "(%s) ", p->name);
1398 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1399 if (p->owner && ast_bridged_channel(p->owner)) {
1400 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1402 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1404 } else if (!ast_strlen_zero(p->loginchan)) {
1405 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1406 talkingto[0] = '\0';
1407 if (p->acknowledged)
1408 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1410 strncpy(location, "not logged in", sizeof(location) - 1);
1411 talkingto[0] = '\0';
1413 if (!ast_strlen_zero(p->moh))
1414 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1415 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1416 username, location, talkingto, moh);
1418 ast_mutex_unlock(&p->lock);
1421 ast_mutex_unlock(&agentlock);
1422 return RESULT_SUCCESS;
1425 static char show_agents_usage[] =
1426 "Usage: show agents\n"
1427 " Provides summary information on agents.\n";
1429 static char agent_logoff_usage[] =
1430 "Usage: agent logoff <channel> [soft]\n"
1431 " Sets an agent as no longer logged in.\n"
1432 " If 'soft' is specified, do not hangup existing calls.\n";
1434 static struct ast_cli_entry cli_show_agents = {
1435 { "show", "agents", NULL }, agents_show,
1436 "Show status of agents", show_agents_usage, NULL };
1438 static struct ast_cli_entry cli_agent_logoff = {
1439 { "agent", "logoff", NULL }, agent_logoff_cmd,
1440 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1442 STANDARD_LOCAL_USER;
1445 /*--- __login_exec: Log in agent application ---*/
1446 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1450 int max_login_tries = maxlogintries;
1451 struct agent_pvt *p;
1452 struct localuser *u;
1454 int login_state = 0;
1455 char user[AST_MAX_AGENT] = "";
1456 char pass[AST_MAX_AGENT];
1457 char agent[AST_MAX_AGENT] = "";
1458 char xpass[AST_MAX_AGENT] = "";
1461 char *opt_user = NULL;
1462 char *options = NULL;
1465 char *tmpoptions = NULL;
1466 char *context = NULL;
1468 int play_announcement = 1;
1469 char agent_goodbye[AST_MAX_FILENAME_LEN];
1470 int update_cdr = updatecdr;
1471 char *filename = "agent-loginok";
1473 strcpy(agent_goodbye, agentgoodbye);
1476 /* Parse the arguments XXX Check for failure XXX */
1477 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1479 /* Set Channel Specific Login Overrides */
1480 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1481 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1482 if (max_login_tries < 0)
1483 max_login_tries = 0;
1484 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1485 if (option_verbose > 2)
1486 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);
1488 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1489 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1493 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1494 if (option_verbose > 2)
1495 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1497 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1498 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1499 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1500 if (option_verbose > 2)
1501 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1503 /* End Channel Specific Login Overrides */
1504 /* Read command line options */
1506 options = strchr(opt_user, '|');
1511 context = strchr(options, '@');
1517 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1524 option = (char)options[0];
1525 if ((option >= 0) && (option <= '9'))
1531 play_announcement = 0;
1533 badoption[0] = option;
1534 badoption[1] = '\0';
1535 tmpoptions=badoption;
1536 if (option_verbose > 2)
1537 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1543 /* End command line options */
1545 if (chan->_state != AST_STATE_UP)
1546 res = ast_answer(chan);
1548 if( opt_user && !ast_strlen_zero(opt_user))
1549 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1551 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1553 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1555 /* Check for password */
1556 ast_mutex_lock(&agentlock);
1559 if (!strcmp(p->agent, user) && !p->pending)
1560 strncpy(xpass, p->password, sizeof(xpass) - 1);
1563 ast_mutex_unlock(&agentlock);
1565 if (!ast_strlen_zero(xpass))
1566 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1570 errmsg = "agent-incorrect";
1573 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1576 /* Check again for accuracy */
1577 ast_mutex_lock(&agentlock);
1580 ast_mutex_lock(&p->lock);
1581 if (!strcmp(p->agent, user) &&
1582 !strcmp(p->password, pass) && !p->pending) {
1583 login_state = 1; /* Successful Login */
1584 /* Set Channel Specific Agent Overides */
1585 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1586 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1588 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1592 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1593 if (option_verbose > 2)
1594 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1596 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1597 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1598 if (p->autologoff < 0)
1600 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1601 if (option_verbose > 2)
1602 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1604 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1605 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1606 if (p->wrapuptime < 0)
1608 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1609 if (option_verbose > 2)
1610 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1612 /* End Channel Specific Agent Overides */
1614 char last_loginchan[80] = "";
1616 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1619 char tmpchan[AST_MAX_BUF] = "";
1621 /* Retrieve login chan */
1624 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1627 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1628 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1632 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1636 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);
1637 res = ast_streamfile(chan, "invalid", chan->language);
1639 res = ast_waitstream(chan, AST_DIGIT_ANY);
1652 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1653 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1655 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1656 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1658 if (ast_strlen_zero(p->loginchan)) {
1660 filename = "agent-loggedoff";
1662 p->acknowledged = 0;
1663 /* store/clear the global variable that stores agentid based on the callerid */
1664 if (chan->cid.cid_num) {
1665 char agentvar[AST_MAX_BUF];
1666 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1667 if (ast_strlen_zero(p->loginchan))
1668 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1670 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1672 if(update_cdr && chan->cdr)
1673 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1677 p->loginchan[0] = '\0';
1678 p->acknowledged = 0;
1680 ast_mutex_unlock(&p->lock);
1681 ast_mutex_unlock(&agentlock);
1682 if( !res && play_announcement==1 )
1683 res = ast_streamfile(chan, filename, chan->language);
1685 ast_waitstream(chan, "");
1686 ast_mutex_lock(&agentlock);
1687 ast_mutex_lock(&p->lock);
1689 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1691 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1694 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1696 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1698 /* Check once more just in case */
1701 if (callbackmode && !res) {
1702 /* Just say goodbye and be done with it */
1703 if (!ast_strlen_zero(p->loginchan)) {
1704 if (p->loginstart == 0)
1705 time(&p->loginstart);
1706 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1710 p->agent, p->loginchan, chan->uniqueid);
1711 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1712 if (option_verbose > 1)
1713 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1714 ast_device_state_changed("Agent/%s", p->agent);
1716 logintime = time(NULL) - p->loginstart;
1718 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1721 "Logintime: %ld\r\n"
1723 p->agent, last_loginchan, logintime, chan->uniqueid);
1724 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1725 if (option_verbose > 1)
1726 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1727 ast_device_state_changed("Agent/%s", p->agent);
1729 ast_mutex_unlock(&agentlock);
1731 res = ast_safe_sleep(chan, 500);
1732 ast_mutex_unlock(&p->lock);
1733 if (persistent_agents)
1736 #ifdef HONOR_MUSIC_CLASS
1737 /* check if the moh class was changed with setmusiconhold */
1738 if (*(chan->musicclass))
1739 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1741 ast_moh_start(chan, p->moh);
1742 if (p->loginstart == 0)
1743 time(&p->loginstart);
1744 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1748 p->agent, chan->name, chan->uniqueid);
1749 if (update_cdr && chan->cdr)
1750 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1751 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1752 if (option_verbose > 1)
1753 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1754 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1755 /* Login this channel and wait for it to
1761 check_availability(p, 0);
1762 ast_mutex_unlock(&p->lock);
1763 ast_mutex_unlock(&agentlock);
1764 ast_device_state_changed("Agent/%s", p->agent);
1766 ast_mutex_lock(&p->lock);
1767 if (p->chan != chan)
1769 ast_mutex_unlock(&p->lock);
1770 /* Yield here so other interested threads can kick in. */
1775 ast_mutex_lock(&agentlock);
1776 ast_mutex_lock(&p->lock);
1777 if (p->lastdisc.tv_sec) {
1778 gettimeofday(&tv, NULL);
1779 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1780 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1782 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1783 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1787 check_availability(p, 0);
1790 ast_mutex_unlock(&p->lock);
1791 ast_mutex_unlock(&agentlock);
1792 /* Synchronize channel ownership between call to agent and itself. */
1793 ast_mutex_lock( &p->app_lock );
1794 ast_mutex_lock(&p->lock);
1795 p->owning_app = pthread_self();
1796 ast_mutex_unlock(&p->lock);
1798 res = agent_ack_sleep(p);
1800 res = ast_safe_sleep_conditional( chan, 1000,
1801 agent_cont_sleep, p );
1802 ast_mutex_unlock( &p->app_lock );
1803 if ((p->ackcall > 1) && (res == 1)) {
1804 ast_mutex_lock(&agentlock);
1805 ast_mutex_lock(&p->lock);
1806 check_availability(p, 0);
1807 ast_mutex_unlock(&p->lock);
1808 ast_mutex_unlock(&agentlock);
1813 ast_mutex_lock(&p->lock);
1814 if (res && p->owner)
1815 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1816 /* Log us off if appropriate */
1817 if (p->chan == chan)
1819 p->acknowledged = 0;
1820 logintime = time(NULL) - p->loginstart;
1822 ast_mutex_unlock(&p->lock);
1823 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1825 "Logintime: %ld\r\n"
1827 p->agent, logintime, chan->uniqueid);
1828 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1829 if (option_verbose > 1)
1830 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1831 /* If there is no owner, go ahead and kill it now */
1832 ast_device_state_changed("Agent/%s", p->agent);
1833 if (p->dead && !p->owner) {
1834 ast_mutex_destroy(&p->lock);
1835 ast_mutex_destroy(&p->app_lock);
1840 ast_mutex_unlock(&p->lock);
1845 ast_mutex_unlock(&p->lock);
1846 errmsg = "agent-alreadyon";
1851 ast_mutex_unlock(&p->lock);
1855 ast_mutex_unlock(&agentlock);
1857 if (!res && (max_login_tries==0 || tries < max_login_tries))
1858 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1861 LOCAL_USER_REMOVE(u);
1863 res = ast_safe_sleep(chan, 500);
1865 /* AgentLogin() exit */
1866 if (!callbackmode) {
1869 /* AgentCallbackLogin() exit*/
1872 if (login_state > 0) {
1873 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1874 if (login_state==1) {
1875 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1876 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1879 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1883 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1885 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1887 /* Do we need to play agent-goodbye now that we will be hanging up? */
1888 if (play_announcement==1) {
1890 res = ast_safe_sleep(chan, 1000);
1891 res = ast_streamfile(chan, agent_goodbye, chan->language);
1893 res = ast_waitstream(chan, "");
1895 res = ast_safe_sleep(chan, 1000);
1898 /* We should never get here if next priority exists when in callbackmode */
1902 static int login_exec(struct ast_channel *chan, void *data)
1904 return __login_exec(chan, data, 0);
1907 static int callback_exec(struct ast_channel *chan, void *data)
1909 return __login_exec(chan, data, 1);
1912 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1914 int exitifnoagentid = 0;
1916 int changeoutgoing = 0;
1918 char agent[AST_MAX_AGENT], *tmp;
1921 if (strchr(data, 'd'))
1922 exitifnoagentid = 1;
1923 if (strchr(data, 'n'))
1925 if (strchr(data, 'c'))
1928 if (chan->cid.cid_num) {
1929 char agentvar[AST_MAX_BUF];
1930 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1931 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1932 struct agent_pvt *p = agents;
1933 strncpy(agent, tmp, sizeof(agent) - 1);
1934 ast_mutex_lock(&agentlock);
1936 if (!strcasecmp(p->agent, tmp)) {
1937 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1938 __agent_start_monitoring(chan, p, 1);
1943 ast_mutex_unlock(&agentlock);
1948 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);
1953 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");
1955 /* check if there is n + 101 priority */
1957 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1958 chan->priority+=100;
1959 if (option_verbose > 2)
1960 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1962 else if (exitifnoagentid)
1968 /* Dump AgentCallbackLogin agents to the database for persistence
1969 * (basically copied from dump_queue_members() in apps/app_queue.c)
1972 static void dump_agents(void)
1974 struct agent_pvt *cur_agent = NULL;
1977 if (cur_agent->chan != NULL) {
1978 cur_agent = cur_agent->next;
1981 if (!ast_strlen_zero(cur_agent->loginchan)) {
1982 if (ast_db_put(pa_family, cur_agent->agent, cur_agent->loginchan)) {
1983 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
1986 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n",
1987 cur_agent->agent, cur_agent->loginchan);
1992 /* Delete - no agent or there is an error */
1993 ast_db_del(pa_family, cur_agent->agent);
1995 cur_agent = cur_agent->next;
1999 /* Reload the persistent agents from astdb */
2000 static void reload_agents(void)
2003 struct ast_db_entry *pa_db_tree = NULL;
2004 int pa_family_len = 0;
2005 struct agent_pvt *cur_agent = NULL;
2006 char agent_data[80];
2008 pa_db_tree = ast_db_gettree(pa_family, NULL);
2010 pa_family_len = strlen(pa_family);
2011 ast_mutex_lock(&agentlock);
2012 while (pa_db_tree) {
2013 pa_agent_num = pa_db_tree->key + pa_family_len + 2;
2016 ast_mutex_lock(&cur_agent->lock);
2018 if (strcmp(pa_agent_num, cur_agent->agent) == 0)
2021 ast_mutex_unlock(&cur_agent->lock);
2022 cur_agent = cur_agent->next;
2025 ast_db_del(pa_family, pa_agent_num);
2026 pa_db_tree = pa_db_tree->next;
2029 ast_mutex_unlock(&cur_agent->lock);
2030 if (!ast_db_get(pa_family, pa_agent_num, agent_data, 80)) {
2032 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n",
2033 cur_agent->agent, agent_data);
2035 strncpy(cur_agent->loginchan,agent_data,80);
2036 if (cur_agent->loginstart == 0)
2037 time(&cur_agent->loginstart);
2038 ast_device_state_changed("Agent/%s", cur_agent->agent);
2040 pa_db_tree = pa_db_tree->next;
2042 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2043 ast_mutex_unlock(&agentlock);
2045 ast_db_freetree(pa_db_tree);
2051 /*--- agent_devicestate: Part of PBX channel interface ---*/
2052 static int agent_devicestate(void *data)
2054 struct agent_pvt *p;
2056 ast_group_t groupmatch;
2059 int res = AST_DEVICE_INVALID;
2062 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2063 groupmatch = (1 << groupoff);
2064 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2065 groupmatch = (1 << groupoff);
2071 /* Check actual logged in agents first */
2072 ast_mutex_lock(&agentlock);
2075 ast_mutex_lock(&p->lock);
2076 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2078 if (res != AST_DEVICE_INUSE)
2079 res = AST_DEVICE_BUSY;
2081 if (res == AST_DEVICE_BUSY)
2082 res = AST_DEVICE_INUSE;
2083 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2084 if (res == AST_DEVICE_INVALID)
2085 res = AST_DEVICE_UNKNOWN;
2086 } else if (res == AST_DEVICE_INVALID)
2087 res = AST_DEVICE_UNAVAILABLE;
2089 if (!strcmp(data, p->agent)) {
2090 ast_mutex_unlock(&p->lock);
2094 ast_mutex_unlock(&p->lock);
2097 ast_mutex_unlock(&agentlock);
2101 /*--- load_module: Initialize channel module ---*/
2104 /* Make sure we can register our agent channel type */
2105 if (ast_channel_register_ex(channeltype, tdesc, capability, agent_request, agent_devicestate)) {
2106 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2109 /* Dialplan applications */
2110 ast_register_application(app, login_exec, synopsis, descrip);
2111 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2112 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2113 /* Manager command */
2114 ast_manager_register2("Agents", 0, action_agents, "Agents", mandescr_agents);
2115 /* CLI Application */
2116 ast_cli_register(&cli_show_agents);
2117 ast_cli_register(&cli_agent_logoff);
2118 /* Read in the config */
2119 read_agent_config();
2120 if (persistent_agents)
2127 read_agent_config();
2128 if (persistent_agents)
2135 struct agent_pvt *p;
2136 /* First, take us out of the channel loop */
2137 /* Unregister CLI application */
2138 ast_cli_unregister(&cli_show_agents);
2139 ast_cli_unregister(&cli_agent_logoff);
2140 /* Unregister dialplan applications */
2141 ast_unregister_application(app);
2142 ast_unregister_application(app2);
2143 ast_unregister_application(app3);
2144 /* Unregister manager command */
2145 ast_manager_unregister("Agents");
2146 /* Unregister channel */
2147 ast_channel_unregister(channeltype);
2148 if (!ast_mutex_lock(&agentlock)) {
2149 /* Hangup all interfaces if they have an owner */
2153 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2157 ast_mutex_unlock(&agentlock);
2159 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2168 ast_mutex_lock(&usecnt_lock);
2170 ast_mutex_unlock(&usecnt_lock);
2176 return ASTERISK_GPL_KEY;