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
13 /** @file chan_agent.c
21 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <sys/signal.h>
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
33 #include "asterisk/lock.h"
34 #include "asterisk/channel.h"
35 #include "asterisk/config.h"
36 #include "asterisk/logger.h"
37 #include "asterisk/module.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/options.h"
40 #include "asterisk/lock.h"
41 #include "asterisk/sched.h"
42 #include "asterisk/io.h"
43 #include "asterisk/rtp.h"
44 #include "asterisk/acl.h"
45 #include "asterisk/callerid.h"
46 #include "asterisk/file.h"
47 #include "asterisk/cli.h"
48 #include "asterisk/app.h"
49 #include "asterisk/musiconhold.h"
50 #include "asterisk/manager.h"
51 #include "asterisk/features.h"
52 #include "asterisk/utils.h"
53 #include "asterisk/causes.h"
54 #include "asterisk/astdb.h"
55 #include "asterisk/devicestate.h"
57 static const char desc[] = "Agent Proxy Channel";
58 static const char channeltype[] = "Agent";
59 static const char tdesc[] = "Call Agent Proxy Channel";
60 static const char config[] = "agents.conf";
62 static const char app[] = "AgentLogin";
63 static const char app2[] = "AgentCallbackLogin";
64 static const char app3[] = "AgentMonitorOutgoing";
66 static const char synopsis[] = "Call agent login";
67 static const char synopsis2[] = "Call agent callback login";
68 static const char synopsis3[] = "Record agent's outgoing call";
70 static const char descrip[] =
71 " AgentLogin([AgentNo][|options]):\n"
72 "Asks the agent to login to the system. Always returns -1. While\n"
73 "logged in, the agent can receive calls and will hear a 'beep'\n"
74 "when a new call comes in. The agent can dump the call by pressing\n"
76 "The option string may contain zero or more of the following characters:\n"
77 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
79 static const char descrip2[] =
80 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
81 "Asks the agent to login to the system with callback.\n"
82 "The agent's callback extension is called (optionally with the specified\n"
84 "The option string may contain zero or more of the following characters:\n"
85 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
87 static const char descrip3[] =
88 " AgentMonitorOutgoing([options]):\n"
89 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
90 "comparision of the callerid of the current interface and the global variable \n"
91 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
92 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
93 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
95 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
96 "the agentid are not specified it'll look for n+101 priority.\n"
98 " 'd' - make the app return -1 if there is an error condition and there is\n"
99 " no extension n+101\n"
100 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
101 " 'n' - don't generate the warnings when there is no callerid or the\n"
102 " agentid is not known.\n"
103 " It's handy if you want to have one context for agent and non-agent calls.\n";
105 static const char mandescr_agents[] =
106 "Description: Will list info about all possible agents.\n"
109 static const char mandescr_agent_logoff[] =
110 "Description: Sets an agent as no longer logged in.\n"
111 "Variables: (Names marked with * are required)\n"
112 " *Agent: Agent ID of the agent to log off\n"
113 " Soft: Set to 'true' to not hangup existing calls\n";
115 static const char mandescr_agent_callback_login[] =
116 "Description: Sets an agent as logged in with callback.\n"
117 "Variables: (Names marked with * are required)\n"
118 " *Agent: Agent ID of the agent to login\n"
119 " *Extension: Extension to use for callback\n"
120 " Context: Context to use for callback\n"
121 " AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
122 " WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
124 static char moh[80] = "default";
126 #define AST_MAX_AGENT 80 /**< Agent ID or Password max length */
127 #define AST_MAX_BUF 256
128 #define AST_MAX_FILENAME_LEN 256
130 /** Persistent Agents astdb family */
131 static const char pa_family[] = "/Agents";
132 /** The maximum lengh of each persistent member agent database entry */
133 #define PA_MAX_LEN 2048
134 /** queues.conf [general] option */
135 static int persistent_agents = 0;
136 static void dump_agents(void);
138 static ast_group_t group;
139 static int autologoff;
140 static int wrapuptime;
143 static int maxlogintries = 3;
144 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
146 static int usecnt =0;
147 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
149 /* Protect the interface list (of pvt's) */
150 AST_MUTEX_DEFINE_STATIC(agentlock);
152 static int recordagentcalls = 0;
153 static char recordformat[AST_MAX_BUF] = "";
154 static char recordformatext[AST_MAX_BUF] = "";
155 static int createlink = 0;
156 static char urlprefix[AST_MAX_BUF] = "";
157 static char savecallsin[AST_MAX_BUF] = "";
158 static int updatecdr = 0;
159 static char beep[AST_MAX_BUF] = "beep";
161 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
164 * Structure representing an agent.
167 ast_mutex_t lock; /**< Channel private lock */
168 int dead; /**< Poised for destruction? */
169 int pending; /**< Not a real agent -- just pending a match */
170 int abouttograb; /**< About to grab */
171 int autologoff; /**< Auto timeout time */
172 int ackcall; /**< ackcall */
173 time_t loginstart; /**< When agent first logged in (0 when logged off) */
174 time_t start; /**< When call started */
175 struct timeval lastdisc; /**< When last disconnected */
176 int wrapuptime; /**< Wrapup time in ms */
177 ast_group_t group; /**< Group memberships */
178 int acknowledged; /**< Acknowledged */
179 char moh[80]; /**< Which music on hold */
180 char agent[AST_MAX_AGENT]; /**< Agent ID */
181 char password[AST_MAX_AGENT]; /**< Password for Agent login */
182 char name[AST_MAX_AGENT];
183 ast_mutex_t app_lock; /**< Synchronization between owning applications */
184 volatile pthread_t owning_app; /**< Owning application thread id */
185 volatile int app_sleep_cond; /**< Sleep condition for the login app */
186 struct ast_channel *owner; /**< Agent */
187 char loginchan[80]; /**< channel they logged in from */
188 char logincallerid[80]; /**< Caller ID they had when they logged in */
189 struct ast_channel *chan; /**< Channel we use */
190 struct agent_pvt *next; /**< Next Agent in the linked list. */
193 struct agent_pvt *agents = NULL; /**< Holds the list of agents (loaded form agents.conf). */
195 #define CHECK_FORMATS(ast, p) do { \
197 if (ast->nativeformats != p->chan->nativeformats) { \
198 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
199 /* Native formats changed, reset things */ \
200 ast->nativeformats = p->chan->nativeformats; \
201 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
202 ast_set_read_format(ast, ast->readformat); \
203 ast_set_write_format(ast, ast->writeformat); \
205 if (p->chan->readformat != ast->rawreadformat) \
206 ast_set_read_format(p->chan, ast->rawreadformat); \
207 if (p->chan->writeformat != ast->rawwriteformat) \
208 ast_set_write_format(p->chan, ast->rawwriteformat); \
212 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
213 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
214 totally impractical combinations XXX */
216 #define CLEANUP(ast, p) do { \
219 for (x=0;x<AST_MAX_FDS;x++) {\
220 if (x != AST_MAX_FDS - 2) \
221 ast->fds[x] = p->chan->fds[x]; \
223 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
227 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
228 static int agent_devicestate(void *data);
229 static int agent_digit(struct ast_channel *ast, char digit);
230 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
231 static int agent_hangup(struct ast_channel *ast);
232 static int agent_answer(struct ast_channel *ast);
233 static struct ast_frame *agent_read(struct ast_channel *ast);
234 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
235 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
236 static int agent_indicate(struct ast_channel *ast, int condition);
237 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
238 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
240 static const struct ast_channel_tech agent_tech = {
242 .description = tdesc,
244 .requester = agent_request,
245 .devicestate = agent_devicestate,
246 .send_digit = agent_digit,
248 .hangup = agent_hangup,
249 .answer = agent_answer,
251 .write = agent_write,
252 .send_html = agent_sendhtml,
253 .exception = agent_read,
254 .indicate = agent_indicate,
255 .fixup = agent_fixup,
256 .bridged_channel = agent_bridgedchannel,
260 * Unlink (that is, take outside of the linked list) an agent.
262 * @param agent Agent to be unlinked.
264 static void agent_unlink(struct agent_pvt *agent)
266 struct agent_pvt *p, *prev;
269 // Iterate over all agents looking for the one.
272 // Once it wal found, check if it is the first one.
274 // If it is not, tell the previous agent that the next one is the next one of the current (jumping the current).
275 prev->next = agent->next;
277 // If it is the first one, just change the general pointer to point to the second one.
278 agents = agent->next;
288 * Adds an agent to the global list of agents.
290 * @param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
291 * @param pending If it is pending or not.
292 * @return The just created agent.
293 * @sa agent_pvt, agents.
295 static struct agent_pvt *add_agent(char *agent, int pending)
300 char *password = NULL;
303 struct agent_pvt *p, *prev;
305 args = ast_strdupa(agent);
307 // Extract username (agt), password and name from agent (args).
308 if ((argc = ast_separate_app_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) {
312 while (*password && *password < 33) password++;
316 while (*name && *name < 33) name++;
319 ast_log(LOG_WARNING, "A blank agent line!\n");
322 // Are we searching for the agent here ? to see if it exists already ?
326 if (!pending && !strcmp(p->agent, agt))
333 p = malloc(sizeof(struct agent_pvt));
335 memset(p, 0, sizeof(struct agent_pvt));
336 ast_copy_string(p->agent, agt, sizeof(p->agent));
337 ast_mutex_init(&p->lock);
338 ast_mutex_init(&p->app_lock);
339 p->owning_app = (pthread_t) -1;
340 p->app_sleep_cond = 1;
342 p->pending = pending;
354 ast_copy_string(p->password, password ? password : "", sizeof(p->password));
355 ast_copy_string(p->name, name ? name : "", sizeof(p->name));
356 ast_copy_string(p->moh, moh, sizeof(p->moh));
357 p->ackcall = ackcall;
358 p->autologoff = autologoff;
360 /* If someone reduces the wrapuptime and reloads, we want it
361 * to change the wrapuptime immediately on all calls */
362 if (p->wrapuptime > wrapuptime) {
363 struct timeval now = ast_tvnow();
364 /* XXX check what is this exactly */
366 /* We won't be pedantic and check the tv_usec val */
367 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
368 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
369 p->lastdisc.tv_usec = now.tv_usec;
372 p->wrapuptime = wrapuptime;
381 static int agent_cleanup(struct agent_pvt *p)
383 struct ast_channel *chan = p->owner;
385 chan->tech_pvt = NULL;
386 p->app_sleep_cond = 1;
387 /* Release ownership of the agent to other threads (presumably running the login app). */
388 ast_mutex_unlock(&p->app_lock);
390 ast_channel_free(chan);
392 ast_mutex_destroy(&p->lock);
393 ast_mutex_destroy(&p->app_lock);
399 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
401 static int agent_answer(struct ast_channel *ast)
403 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
407 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
409 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
410 char filename[AST_MAX_BUF];
415 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
416 /* substitute . for - */
417 if ((pointer = strchr(filename, '.')))
419 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
420 ast_monitor_start(ast, recordformat, tmp, needlock);
421 ast_monitor_setjoinfiles(ast, 1);
422 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
424 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
427 ast->cdr = ast_cdr_alloc();
428 ast_cdr_setuserfield(ast, tmp2);
431 ast_log(LOG_ERROR, "Recording already started on that call.\n");
435 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
437 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
440 static struct ast_frame *agent_read(struct ast_channel *ast)
442 struct agent_pvt *p = ast->tech_pvt;
443 struct ast_frame *f = NULL;
444 static struct ast_frame null_frame = { AST_FRAME_NULL, };
445 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
446 ast_mutex_lock(&p->lock);
447 CHECK_FORMATS(ast, p);
449 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
450 if (ast->fdno == AST_MAX_FDS - 3)
451 p->chan->fdno = AST_MAX_FDS - 2;
453 p->chan->fdno = ast->fdno;
454 f = ast_read(p->chan);
458 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
460 p->chan->_bridge = NULL;
461 /* Note that we don't hangup if it's not a callback because Asterisk will do it
462 for us when the PBX instance that called login finishes */
463 if (!ast_strlen_zero(p->loginchan)) {
465 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
467 if (p->wrapuptime && p->acknowledged)
468 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
474 /* if acknowledgement is not required, and the channel is up, we may have missed
475 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
476 if (!p->ackcall && !p->acknowledged && p->chan->_state == AST_STATE_UP)
478 switch (f->frametype) {
479 case AST_FRAME_CONTROL:
480 if (f->subclass == AST_CONTROL_ANSWER) {
482 if (option_verbose > 2)
483 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
484 /* Don't pass answer along */
489 /* Use the builtin answer frame for the
490 recording start check below. */
497 if (!p->acknowledged && (f->subclass == '#')) {
498 if (option_verbose > 2)
499 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
503 } else if (f->subclass == '*') {
504 /* terminates call */
509 case AST_FRAME_VOICE:
510 /* don't pass voice until the call is acknowledged */
511 if (!p->acknowledged) {
520 if (p->chan && !p->chan->_bridge) {
521 if (strcasecmp(p->chan->type, "Local")) {
522 p->chan->_bridge = ast;
524 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
527 ast_mutex_unlock(&p->lock);
528 if (recordagentcalls && f == &answer_frame)
529 agent_start_monitoring(ast,0);
533 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
535 struct agent_pvt *p = ast->tech_pvt;
537 ast_mutex_lock(&p->lock);
539 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
540 ast_mutex_unlock(&p->lock);
544 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
546 struct agent_pvt *p = ast->tech_pvt;
548 CHECK_FORMATS(ast, p);
549 ast_mutex_lock(&p->lock);
551 if ((f->frametype != AST_FRAME_VOICE) ||
552 (f->subclass == p->chan->writeformat)) {
553 res = ast_write(p->chan, f);
555 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
561 ast_mutex_unlock(&p->lock);
565 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
567 struct agent_pvt *p = newchan->tech_pvt;
568 ast_mutex_lock(&p->lock);
569 if (p->owner != oldchan) {
570 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
571 ast_mutex_unlock(&p->lock);
575 ast_mutex_unlock(&p->lock);
579 static int agent_indicate(struct ast_channel *ast, int condition)
581 struct agent_pvt *p = ast->tech_pvt;
583 ast_mutex_lock(&p->lock);
585 res = ast_indicate(p->chan, condition);
588 ast_mutex_unlock(&p->lock);
592 static int agent_digit(struct ast_channel *ast, char digit)
594 struct agent_pvt *p = ast->tech_pvt;
596 ast_mutex_lock(&p->lock);
598 res = p->chan->tech->send_digit(p->chan, digit);
601 ast_mutex_unlock(&p->lock);
605 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
607 struct agent_pvt *p = ast->tech_pvt;
610 ast_mutex_lock(&p->lock);
614 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
615 newstate = AST_STATE_DIALING;
618 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
621 ast_mutex_unlock(&p->lock);
623 ast_setstate(ast, newstate);
625 } else if (!ast_strlen_zero(p->loginchan)) {
627 /* Call on this agent */
628 if (option_verbose > 2)
629 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
630 if (p->chan->cid.cid_num)
631 free(p->chan->cid.cid_num);
632 if (ast->cid.cid_num)
633 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
635 p->chan->cid.cid_num = NULL;
636 if (p->chan->cid.cid_name)
637 free(p->chan->cid.cid_name);
638 if (ast->cid.cid_name)
639 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
641 p->chan->cid.cid_name = NULL;
642 ast_channel_inherit_variables(ast, p->chan);
643 res = ast_call(p->chan, p->loginchan, 0);
645 ast_mutex_unlock(&p->lock);
648 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
649 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
650 res = ast_streamfile(p->chan, beep, p->chan->language);
651 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
653 res = ast_waitstream(p->chan, "");
654 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
657 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
658 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
660 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
667 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
668 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
670 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
674 /* Call is immediately up, or might need ack */
676 newstate = AST_STATE_RINGING;
678 newstate = AST_STATE_UP;
679 if (recordagentcalls)
680 agent_start_monitoring(ast,0);
686 ast_mutex_unlock(&p->lock);
688 ast_setstate(ast, newstate);
692 /* store/clear the global variable that stores agentid based on the callerid */
693 static void set_agentbycallerid(const char *callerid, const char *agent)
695 char buf[AST_MAX_BUF];
697 /* if there is no Caller ID, nothing to do */
698 if (!callerid || ast_strlen_zero(callerid))
701 snprintf(buf, sizeof(buf), "%s_%s",GETAGENTBYCALLERID, callerid);
702 pbx_builtin_setvar_helper(NULL, buf, agent);
705 static int agent_hangup(struct ast_channel *ast)
707 struct agent_pvt *p = ast->tech_pvt;
709 ast_mutex_lock(&p->lock);
711 ast->tech_pvt = NULL;
712 p->app_sleep_cond = 1;
715 /* if they really are hung up then set start to 0 so the test
716 * later if we're called on an already downed channel
717 * doesn't cause an agent to be logged out like when
718 * agent_request() is followed immediately by agent_hangup()
719 * as in apps/app_chanisavail.c:chanavail_exec()
722 ast_mutex_lock(&usecnt_lock);
724 ast_mutex_unlock(&usecnt_lock);
726 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
727 if (p->start && (ast->_state != AST_STATE_UP)) {
728 howlong = time(NULL) - p->start;
730 } else if (ast->_state == AST_STATE_RESERVED) {
735 p->chan->_bridge = NULL;
736 /* If they're dead, go ahead and hang up on the agent now */
737 if (!ast_strlen_zero(p->loginchan)) {
738 /* Store last disconnect time */
739 if (p->wrapuptime && p->acknowledged)
740 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
742 p->lastdisc = ast_tv(0,0);
744 /* Recognize the hangup and pass it along immediately */
748 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
749 if (howlong && p->autologoff && (howlong > p->autologoff)) {
750 char agent[AST_MAX_AGENT] = "";
751 long logintime = time(NULL) - p->loginstart;
753 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
754 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
758 "Reason: Autologoff\r\n"
760 p->agent, p->loginchan, logintime, ast->uniqueid);
761 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
762 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
763 set_agentbycallerid(p->logincallerid, NULL);
764 p->loginchan[0] = '\0';
765 p->logincallerid[0] = '\0';
767 } else if (p->dead) {
768 ast_mutex_lock(&p->chan->lock);
769 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
770 ast_mutex_unlock(&p->chan->lock);
772 ast_mutex_lock(&p->chan->lock);
773 ast_moh_start(p->chan, p->moh);
774 ast_mutex_unlock(&p->chan->lock);
777 ast_mutex_unlock(&p->lock);
778 ast_device_state_changed("Agent/%s", p->agent);
781 ast_mutex_lock(&agentlock);
783 ast_mutex_unlock(&agentlock);
785 if (p->abouttograb) {
786 /* Let the "about to grab" thread know this isn't valid anymore, and let it
789 } else if (p->dead) {
790 ast_mutex_destroy(&p->lock);
791 ast_mutex_destroy(&p->app_lock);
795 /* Not dead -- check availability now */
796 ast_mutex_lock(&p->lock);
797 /* Store last disconnect time */
798 p->lastdisc = ast_tvnow();
799 ast_mutex_unlock(&p->lock);
801 /* Release ownership of the agent to other threads (presumably running the login app). */
802 ast_mutex_unlock(&p->app_lock);
807 static int agent_cont_sleep( void *data )
812 p = (struct agent_pvt *)data;
814 ast_mutex_lock(&p->lock);
815 res = p->app_sleep_cond;
816 if (p->lastdisc.tv_sec) {
817 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime)
820 ast_mutex_unlock(&p->lock);
823 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
828 static int agent_ack_sleep( void *data )
835 /* Wait a second and look for something */
837 p = (struct agent_pvt *)data;
840 to = ast_waitfor(p->chan, to);
849 f = ast_read(p->chan);
854 if (f->frametype == AST_FRAME_DTMF)
859 ast_mutex_lock(&p->lock);
860 if (!p->app_sleep_cond) {
861 ast_mutex_unlock(&p->lock);
864 } else if (res == '#') {
865 ast_mutex_unlock(&p->lock);
869 ast_mutex_unlock(&p->lock);
877 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
880 struct ast_channel *ret=NULL;
883 p = bridge->tech_pvt;
885 ret = bridge->_bridge;
886 else if (chan == bridge->_bridge)
889 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
893 /*--- agent_new: Create new agent channel ---*/
894 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
896 struct ast_channel *tmp;
897 struct ast_frame null_frame = { AST_FRAME_NULL };
900 ast_log(LOG_WARNING, "No channel? :(\n");
904 tmp = ast_channel_alloc(0);
906 tmp->tech = &agent_tech;
908 tmp->nativeformats = p->chan->nativeformats;
909 tmp->writeformat = p->chan->writeformat;
910 tmp->rawwriteformat = p->chan->writeformat;
911 tmp->readformat = p->chan->readformat;
912 tmp->rawreadformat = p->chan->readformat;
913 ast_copy_string(tmp->language, p->chan->language, sizeof(tmp->language));
914 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
915 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
917 tmp->nativeformats = AST_FORMAT_SLINEAR;
918 tmp->writeformat = AST_FORMAT_SLINEAR;
919 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
920 tmp->readformat = AST_FORMAT_SLINEAR;
921 tmp->rawreadformat = AST_FORMAT_SLINEAR;
924 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
926 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
927 tmp->type = channeltype;
928 /* Safe, agentlock already held */
929 ast_setstate(tmp, state);
932 ast_mutex_lock(&usecnt_lock);
934 ast_mutex_unlock(&usecnt_lock);
935 ast_update_use_count();
937 /* Wake up and wait for other applications (by definition the login app)
938 * to release this channel). Takes ownership of the agent channel
939 * to this thread only.
940 * For signalling the other thread, ast_queue_frame is used until we
941 * can safely use signals for this purpose. The pselect() needs to be
942 * implemented in the kernel for this.
944 p->app_sleep_cond = 0;
945 if( ast_mutex_trylock(&p->app_lock) )
948 ast_queue_frame(p->chan, &null_frame);
949 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
950 ast_mutex_lock(&p->app_lock);
951 ast_mutex_lock(&p->lock);
955 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
957 tmp->tech_pvt = NULL;
958 p->app_sleep_cond = 1;
959 ast_channel_free( tmp );
960 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
961 ast_mutex_unlock(&p->app_lock);
965 p->owning_app = pthread_self();
966 /* After the above step, there should not be any blockers. */
968 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
969 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
972 ast_moh_stop(p->chan);
975 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
981 * Read configuration data. The file named agents.conf.
983 * @returns Always 0, or so it seems.
985 static int read_agent_config(void)
987 struct ast_config *cfg;
988 struct ast_variable *v;
989 struct agent_pvt *p, *pl, *pn;
996 cfg = ast_config_load(config);
998 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1001 ast_mutex_lock(&agentlock);
1007 strcpy(moh, "default");
1008 /* set the default recording values */
1009 recordagentcalls = 0;
1011 strcpy(recordformat, "wav");
1012 strcpy(recordformatext, "wav");
1013 urlprefix[0] = '\0';
1014 savecallsin[0] = '\0';
1016 /* Read in [general] section for persistance */
1017 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1018 persistent_agents = ast_true(general_val);
1020 /* Read in the [agents] section */
1021 v = ast_variable_browse(cfg, "agents");
1023 /* Create the interface list */
1024 if (!strcasecmp(v->name, "agent")) {
1025 add_agent(v->value, 0);
1026 } else if (!strcasecmp(v->name, "group")) {
1027 group = ast_get_group(v->value);
1028 } else if (!strcasecmp(v->name, "autologoff")) {
1029 autologoff = atoi(v->value);
1032 } else if (!strcasecmp(v->name, "ackcall")) {
1033 if (!strcasecmp(v->value, "always"))
1035 else if (ast_true(v->value))
1039 } else if (!strcasecmp(v->name, "wrapuptime")) {
1040 wrapuptime = atoi(v->value);
1043 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1044 maxlogintries = atoi(v->value);
1045 if (maxlogintries < 0)
1047 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1048 strcpy(agentgoodbye,v->value);
1049 } else if (!strcasecmp(v->name, "musiconhold")) {
1050 ast_copy_string(moh, v->value, sizeof(moh));
1051 } else if (!strcasecmp(v->name, "updatecdr")) {
1052 if (ast_true(v->value))
1056 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1057 recordagentcalls = ast_true(v->value);
1058 } else if (!strcasecmp(v->name, "createlink")) {
1059 createlink = ast_true(v->value);
1060 } else if (!strcasecmp(v->name, "recordformat")) {
1061 ast_copy_string(recordformat, v->value, sizeof(recordformat));
1062 if (!strcasecmp(v->value, "wav49"))
1063 strcpy(recordformatext, "WAV");
1065 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1066 } else if (!strcasecmp(v->name, "urlprefix")) {
1067 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1068 if (urlprefix[strlen(urlprefix) - 1] != '/')
1069 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1070 } else if (!strcasecmp(v->name, "savecallsin")) {
1071 if (v->value[0] == '/')
1072 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1074 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1075 if (savecallsin[strlen(savecallsin) - 1] != '/')
1076 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1077 } else if (!strcasecmp(v->name, "custom_beep")) {
1078 ast_copy_string(beep, v->value, sizeof(beep));
1092 /* Destroy if appropriate */
1095 ast_mutex_destroy(&p->lock);
1096 ast_mutex_destroy(&p->app_lock);
1099 /* Cause them to hang up */
1100 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1107 ast_mutex_unlock(&agentlock);
1108 ast_config_destroy(cfg);
1112 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1114 struct ast_channel *chan=NULL, *parent=NULL;
1115 struct agent_pvt *p;
1119 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1121 ast_mutex_lock(&agentlock);
1124 if (p == newlyavailable) {
1128 ast_mutex_lock(&p->lock);
1129 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1131 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1132 /* We found a pending call, time to merge */
1133 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1136 ast_mutex_unlock(&p->lock);
1139 ast_mutex_unlock(&p->lock);
1143 ast_mutex_unlock(&agentlock);
1144 if (parent && chan) {
1145 if (newlyavailable->ackcall > 1) {
1146 /* Don't do beep here */
1149 if (option_debug > 2)
1150 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1151 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1152 if (option_debug > 2)
1153 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1155 res = ast_waitstream(newlyavailable->chan, "");
1156 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1160 /* Note -- parent may have disappeared */
1161 if (p->abouttograb) {
1162 newlyavailable->acknowledged = 1;
1163 /* Safe -- agent lock already held */
1164 ast_setstate(parent, AST_STATE_UP);
1165 ast_setstate(chan, AST_STATE_UP);
1166 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1167 /* Go ahead and mark the channel as a zombie so that masquerade will
1168 destroy it for us, and we need not call ast_hangup */
1169 ast_mutex_lock(&parent->lock);
1170 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1171 ast_channel_masquerade(parent, chan);
1172 ast_mutex_unlock(&parent->lock);
1176 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1177 agent_cleanup(newlyavailable);
1181 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1182 agent_cleanup(newlyavailable);
1188 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1190 struct agent_pvt *p;
1193 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1195 ast_mutex_lock(&agentlock);
1198 if (p == newlyavailable) {
1202 ast_mutex_lock(&p->lock);
1203 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1205 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1206 ast_mutex_unlock(&p->lock);
1209 ast_mutex_unlock(&p->lock);
1213 ast_mutex_unlock(&agentlock);
1215 ast_mutex_unlock(&newlyavailable->lock);
1216 if (option_debug > 2)
1217 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1218 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1219 if (option_debug > 2)
1220 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1222 res = ast_waitstream(newlyavailable->chan, "");
1224 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1226 ast_mutex_lock(&newlyavailable->lock);
1231 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1232 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1234 struct agent_pvt *p;
1235 struct ast_channel *chan = NULL;
1237 ast_group_t groupmatch;
1244 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1245 groupmatch = (1 << groupoff);
1246 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1247 groupmatch = (1 << groupoff);
1253 /* Check actual logged in agents first */
1254 ast_mutex_lock(&agentlock);
1257 ast_mutex_lock(&p->lock);
1258 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1259 ast_strlen_zero(p->loginchan)) {
1262 if (!p->lastdisc.tv_sec) {
1263 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1264 if (!p->owner && p->chan) {
1266 chan = agent_new(p, AST_STATE_DOWN);
1269 ast_mutex_unlock(&p->lock);
1274 ast_mutex_unlock(&p->lock);
1280 ast_mutex_lock(&p->lock);
1281 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1282 if (p->chan || !ast_strlen_zero(p->loginchan))
1286 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1288 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1289 p->lastdisc = ast_tv(0, 0);
1290 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1291 if (!p->owner && p->chan) {
1292 /* Could still get a fixed agent */
1293 chan = agent_new(p, AST_STATE_DOWN);
1294 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1295 /* Adjustable agent */
1296 p->chan = ast_request("Local", format, p->loginchan, cause);
1298 chan = agent_new(p, AST_STATE_DOWN);
1301 ast_mutex_unlock(&p->lock);
1306 ast_mutex_unlock(&p->lock);
1311 if (!chan && waitforagent) {
1312 /* No agent available -- but we're requesting to wait for one.
1313 Allocate a place holder */
1316 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1317 p = add_agent(data, 1);
1318 p->group = groupmatch;
1319 chan = agent_new(p, AST_STATE_DOWN);
1321 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1324 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1327 *cause = AST_CAUSE_BUSY;
1329 *cause = AST_CAUSE_UNREGISTERED;
1330 ast_mutex_unlock(&agentlock);
1334 static int powerof(unsigned int v)
1337 for (x=0;x<32;x++) {
1338 if (v & (1 << x)) return x;
1343 /*--- action_agents: Manager routine for listing channels */
1344 static int action_agents(struct mansession *s, struct message *m)
1346 char *id = astman_get_header(m,"ActionID");
1347 char idText[256] = "";
1348 struct agent_pvt *p;
1349 char *username = NULL;
1350 char *loginChan = NULL;
1351 char *talkingtoChan = NULL;
1352 char *status = NULL;
1354 if (id && !ast_strlen_zero(id))
1355 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1356 astman_send_ack(s, m, "Agents will follow");
1357 ast_mutex_lock(&agentlock);
1359 ast_mutex_lock(&s->lock);
1361 ast_mutex_lock(&p->lock);
1364 AGENT_LOGGEDOFF - Agent isn't logged in
1365 AGENT_IDLE - Agent is logged in, and waiting for call
1366 AGENT_ONCALL - Agent is logged in, and on a call
1367 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1369 if(!ast_strlen_zero(p->name)) {
1375 /* Set a default status. It 'should' get changed. */
1376 status = "AGENT_UNKNOWN";
1379 loginChan = p->loginchan;
1380 if(p->owner && p->owner->_bridge) {
1381 talkingtoChan = p->chan->cid.cid_num;
1382 status = "AGENT_ONCALL";
1384 talkingtoChan = "n/a";
1385 status = "AGENT_IDLE";
1387 } else if(!ast_strlen_zero(p->loginchan)) {
1388 loginChan = p->loginchan;
1389 talkingtoChan = "n/a";
1390 status = "AGENT_IDLE";
1391 if(p->acknowledged) {
1392 sprintf(loginChan, " %s (Confirmed)", loginChan);
1396 talkingtoChan = "n/a";
1397 status = "AGENT_LOGGEDOFF";
1400 ast_cli(s->fd, "Event: Agents\r\n"
1404 "LoggedInChan: %s\r\n"
1405 "LoggedInTime: %ld\r\n"
1409 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan,idText);
1410 ast_mutex_unlock(&p->lock);
1413 ast_mutex_unlock(&agentlock);
1414 ast_cli(s->fd, "Event: AgentsComplete\r\n"
1417 ast_mutex_unlock(&s->lock);
1422 static int agent_logoff(char *agent, int soft)
1424 struct agent_pvt *p;
1426 int ret = -1; /* Return -1 if no agent if found */
1428 for (p=agents; p; p=p->next) {
1429 if (!strcasecmp(p->agent, agent)) {
1432 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1435 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1438 ret = 0; /* found an agent => return 0 */
1439 logintime = time(NULL) - p->loginstart;
1442 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1445 "Logintime: %ld\r\n",
1446 p->agent, p->loginchan, logintime);
1447 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1448 set_agentbycallerid(p->logincallerid, NULL);
1449 p->loginchan[0] = '\0';
1450 p->logincallerid[0] = '\0';
1451 ast_device_state_changed("Agent/%s", p->agent);
1452 if (persistent_agents)
1461 static int agent_logoff_cmd(int fd, int argc, char **argv)
1466 if (argc < 3 || argc > 4)
1467 return RESULT_SHOWUSAGE;
1468 if (argc == 4 && strcasecmp(argv[3], "soft"))
1469 return RESULT_SHOWUSAGE;
1471 agent = argv[2] + 6;
1472 ret = agent_logoff(agent, argc == 4);
1474 ast_cli(fd, "Logging out %s\n", agent);
1476 return RESULT_SUCCESS;
1479 static int action_agent_logoff(struct mansession *s, struct message *m)
1481 char *agent = astman_get_header(m, "Agent");
1482 char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1484 int ret; /* return value of agent_logoff */
1486 if (!agent || ast_strlen_zero(agent)) {
1487 astman_send_error(s, m, "No agent specified");
1491 if (ast_true(soft_s))
1496 ret = agent_logoff(agent, soft);
1498 astman_send_ack(s, m, "Agent logged out");
1500 astman_send_error(s, m, "No such agent");
1505 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1507 struct agent_pvt *p;
1508 char name[AST_MAX_AGENT];
1512 for (p=agents; p; p=p->next) {
1513 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1514 if (!strncasecmp(word, name, strlen(word))) {
1515 if (++which > state) {
1516 return strdup(name);
1520 } else if (pos == 3 && state == 0) {
1521 return strdup("soft");
1527 * Show agents in cli.
1529 static int agents_show(int fd, int argc, char **argv)
1531 struct agent_pvt *p;
1532 char username[AST_MAX_BUF];
1533 char location[AST_MAX_BUF] = "";
1534 char talkingto[AST_MAX_BUF] = "";
1535 char moh[AST_MAX_BUF];
1536 int count_agents = 0; /* Number of agents configured */
1537 int online_agents = 0; /* Number of online agents */
1538 int offline_agents = 0; /* Number of offline agents */
1540 return RESULT_SHOWUSAGE;
1541 ast_mutex_lock(&agentlock);
1544 ast_mutex_lock(&p->lock);
1547 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1549 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1551 if (!ast_strlen_zero(p->name))
1552 snprintf(username, sizeof(username), "(%s) ", p->name);
1556 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1557 if (p->owner && ast_bridged_channel(p->owner)) {
1558 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1560 strcpy(talkingto, " is idle");
1563 } else if (!ast_strlen_zero(p->loginchan)) {
1564 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1565 talkingto[0] = '\0';
1567 if (p->acknowledged)
1568 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1570 strcpy(location, "not logged in");
1571 talkingto[0] = '\0';
1574 if (!ast_strlen_zero(p->moh))
1575 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1576 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1577 username, location, talkingto, moh);
1580 ast_mutex_unlock(&p->lock);
1583 ast_mutex_unlock(&agentlock);
1584 if ( !count_agents ) {
1585 ast_cli(fd, "No Agents are configured in %s\n",config);
1587 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1591 return RESULT_SUCCESS;
1594 static char show_agents_usage[] =
1595 "Usage: show agents\n"
1596 " Provides summary information on agents.\n";
1598 static char agent_logoff_usage[] =
1599 "Usage: agent logoff <channel> [soft]\n"
1600 " Sets an agent as no longer logged in.\n"
1601 " If 'soft' is specified, do not hangup existing calls.\n";
1603 static struct ast_cli_entry cli_show_agents = {
1604 { "show", "agents", NULL }, agents_show,
1605 "Show status of agents", show_agents_usage, NULL };
1607 static struct ast_cli_entry cli_agent_logoff = {
1608 { "agent", "logoff", NULL }, agent_logoff_cmd,
1609 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1611 STANDARD_LOCAL_USER;
1614 /*--- __login_exec: Log in agent application ---*/
1615 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1619 int max_login_tries = maxlogintries;
1620 struct agent_pvt *p;
1621 struct localuser *u;
1622 int login_state = 0;
1623 char user[AST_MAX_AGENT] = "";
1624 char pass[AST_MAX_AGENT];
1625 char agent[AST_MAX_AGENT] = "";
1626 char xpass[AST_MAX_AGENT] = "";
1629 char *opt_user = NULL;
1630 char *options = NULL;
1633 char *tmpoptions = NULL;
1634 char *context = NULL;
1636 int play_announcement = 1;
1637 char agent_goodbye[AST_MAX_FILENAME_LEN];
1638 int update_cdr = updatecdr;
1639 char *filename = "agent-loginok";
1641 strcpy(agent_goodbye, agentgoodbye);
1644 /* Parse the arguments XXX Check for failure XXX */
1645 ast_copy_string(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION);
1647 /* Set Channel Specific Login Overrides */
1648 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1649 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1650 if (max_login_tries < 0)
1651 max_login_tries = 0;
1652 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1653 if (option_verbose > 2)
1654 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);
1656 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1657 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1661 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1662 if (option_verbose > 2)
1663 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1665 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1666 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1667 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1668 if (option_verbose > 2)
1669 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1671 /* End Channel Specific Login Overrides */
1672 /* Read command line options */
1674 options = strchr(opt_user, '|');
1679 context = strchr(options, '@');
1685 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1692 option = (char)options[0];
1693 if ((option >= 0) && (option <= '9'))
1699 play_announcement = 0;
1701 badoption[0] = option;
1702 badoption[1] = '\0';
1703 tmpoptions=badoption;
1704 if (option_verbose > 2)
1705 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1711 /* End command line options */
1713 if (chan->_state != AST_STATE_UP)
1714 res = ast_answer(chan);
1716 if( opt_user && !ast_strlen_zero(opt_user))
1717 ast_copy_string(user, opt_user, AST_MAX_AGENT);
1719 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1721 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1723 /* Check for password */
1724 ast_mutex_lock(&agentlock);
1727 if (!strcmp(p->agent, user) && !p->pending)
1728 ast_copy_string(xpass, p->password, sizeof(xpass));
1731 ast_mutex_unlock(&agentlock);
1733 if (!ast_strlen_zero(xpass))
1734 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1738 errmsg = "agent-incorrect";
1741 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1744 /* Check again for accuracy */
1745 ast_mutex_lock(&agentlock);
1748 ast_mutex_lock(&p->lock);
1749 if (!strcmp(p->agent, user) &&
1750 !strcmp(p->password, pass) && !p->pending) {
1751 login_state = 1; /* Successful Login */
1753 /* Ensure we can't be gotten until we're done */
1754 gettimeofday(&p->lastdisc, NULL);
1755 p->lastdisc.tv_sec++;
1757 /* Set Channel Specific Agent Overides */
1758 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1759 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1761 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1765 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1766 if (option_verbose > 2)
1767 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1769 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1770 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1771 if (p->autologoff < 0)
1773 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1774 if (option_verbose > 2)
1775 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1777 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1778 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1779 if (p->wrapuptime < 0)
1781 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1782 if (option_verbose > 2)
1783 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1785 /* End Channel Specific Agent Overides */
1787 char last_loginchan[80] = "";
1789 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1792 char tmpchan[AST_MAX_BUF] = "";
1794 /* Retrieve login chan */
1797 ast_copy_string(tmpchan, exten, sizeof(tmpchan));
1800 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1801 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1805 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1809 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);
1810 res = ast_streamfile(chan, "invalid", chan->language);
1812 res = ast_waitstream(chan, AST_DIGIT_ANY);
1825 set_agentbycallerid(p->logincallerid, NULL);
1826 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1827 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1829 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1830 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1832 p->acknowledged = 0;
1833 if (ast_strlen_zero(p->loginchan)) {
1835 filename = "agent-loggedoff";
1837 if (chan->cid.cid_num) {
1838 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1839 set_agentbycallerid(p->logincallerid, p->agent);
1841 p->logincallerid[0] = '\0';
1844 if(update_cdr && chan->cdr)
1845 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1849 p->loginchan[0] = '\0';
1850 p->logincallerid[0] = '\0';
1851 p->acknowledged = 0;
1853 ast_mutex_unlock(&p->lock);
1854 ast_mutex_unlock(&agentlock);
1855 if( !res && play_announcement==1 )
1856 res = ast_streamfile(chan, filename, chan->language);
1858 ast_waitstream(chan, "");
1859 ast_mutex_lock(&agentlock);
1860 ast_mutex_lock(&p->lock);
1862 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1864 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1867 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1869 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1871 /* Check once more just in case */
1874 if (callbackmode && !res) {
1875 /* Just say goodbye and be done with it */
1876 if (!ast_strlen_zero(p->loginchan)) {
1877 if (p->loginstart == 0)
1878 time(&p->loginstart);
1879 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1883 p->agent, p->loginchan, chan->uniqueid);
1884 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1885 if (option_verbose > 1)
1886 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1887 ast_device_state_changed("Agent/%s", p->agent);
1889 logintime = time(NULL) - p->loginstart;
1891 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1894 "Logintime: %ld\r\n"
1896 p->agent, last_loginchan, logintime, chan->uniqueid);
1897 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1898 if (option_verbose > 1)
1899 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1900 ast_device_state_changed("Agent/%s", p->agent);
1902 ast_mutex_unlock(&agentlock);
1904 res = ast_safe_sleep(chan, 500);
1905 ast_mutex_unlock(&p->lock);
1906 if (persistent_agents)
1909 #ifdef HONOR_MUSIC_CLASS
1910 /* check if the moh class was changed with setmusiconhold */
1911 if (*(chan->musicclass))
1912 ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
1914 ast_moh_start(chan, p->moh);
1915 if (p->loginstart == 0)
1916 time(&p->loginstart);
1917 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1921 p->agent, chan->name, chan->uniqueid);
1922 if (update_cdr && chan->cdr)
1923 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1924 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1925 if (option_verbose > 1)
1926 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1927 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1928 /* Login this channel and wait for it to
1934 check_availability(p, 0);
1935 ast_mutex_unlock(&p->lock);
1936 ast_mutex_unlock(&agentlock);
1937 ast_device_state_changed("Agent/%s", p->agent);
1939 ast_mutex_lock(&p->lock);
1940 if (p->chan != chan)
1942 ast_mutex_unlock(&p->lock);
1943 /* Yield here so other interested threads can kick in. */
1948 ast_mutex_lock(&agentlock);
1949 ast_mutex_lock(&p->lock);
1950 if (p->lastdisc.tv_sec) {
1951 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
1953 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1954 p->lastdisc = ast_tv(0, 0);
1958 check_availability(p, 0);
1961 ast_mutex_unlock(&p->lock);
1962 ast_mutex_unlock(&agentlock);
1963 /* Synchronize channel ownership between call to agent and itself. */
1964 ast_mutex_lock( &p->app_lock );
1965 ast_mutex_lock(&p->lock);
1966 p->owning_app = pthread_self();
1967 ast_mutex_unlock(&p->lock);
1969 res = agent_ack_sleep(p);
1971 res = ast_safe_sleep_conditional( chan, 1000,
1972 agent_cont_sleep, p );
1973 ast_mutex_unlock( &p->app_lock );
1974 if ((p->ackcall > 1) && (res == 1)) {
1975 ast_mutex_lock(&agentlock);
1976 ast_mutex_lock(&p->lock);
1977 check_availability(p, 0);
1978 ast_mutex_unlock(&p->lock);
1979 ast_mutex_unlock(&agentlock);
1984 ast_mutex_lock(&p->lock);
1985 if (res && p->owner)
1986 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1987 /* Log us off if appropriate */
1988 if (p->chan == chan)
1990 p->acknowledged = 0;
1991 logintime = time(NULL) - p->loginstart;
1993 ast_mutex_unlock(&p->lock);
1994 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1996 "Logintime: %ld\r\n"
1998 p->agent, logintime, chan->uniqueid);
1999 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2000 if (option_verbose > 1)
2001 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
2002 /* If there is no owner, go ahead and kill it now */
2003 ast_device_state_changed("Agent/%s", p->agent);
2004 if (p->dead && !p->owner) {
2005 ast_mutex_destroy(&p->lock);
2006 ast_mutex_destroy(&p->app_lock);
2011 ast_mutex_unlock(&p->lock);
2016 ast_mutex_unlock(&p->lock);
2017 errmsg = "agent-alreadyon";
2022 ast_mutex_unlock(&p->lock);
2026 ast_mutex_unlock(&agentlock);
2028 if (!res && (max_login_tries==0 || tries < max_login_tries))
2029 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2032 LOCAL_USER_REMOVE(u);
2034 res = ast_safe_sleep(chan, 500);
2036 /* AgentLogin() exit */
2037 if (!callbackmode) {
2040 /* AgentCallbackLogin() exit*/
2043 if (login_state > 0) {
2044 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
2045 if (login_state==1) {
2046 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
2047 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
2050 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
2054 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
2056 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
2058 /* Do we need to play agent-goodbye now that we will be hanging up? */
2059 if (play_announcement==1) {
2061 res = ast_safe_sleep(chan, 1000);
2062 res = ast_streamfile(chan, agent_goodbye, chan->language);
2064 res = ast_waitstream(chan, "");
2066 res = ast_safe_sleep(chan, 1000);
2069 /* We should never get here if next priority exists when in callbackmode */
2073 static int login_exec(struct ast_channel *chan, void *data)
2075 return __login_exec(chan, data, 0);
2078 static int callback_exec(struct ast_channel *chan, void *data)
2080 return __login_exec(chan, data, 1);
2083 static int action_agent_callback_login(struct mansession *s, struct message *m)
2085 char *agent = astman_get_header(m, "Agent");
2086 char *exten = astman_get_header(m, "Exten");
2087 char *context = astman_get_header(m, "Context");
2088 char *wrapuptime_s = astman_get_header(m, "WrapupTime");
2089 char *ackcall_s = astman_get_header(m, "AckCall");
2090 struct agent_pvt *p;
2091 int login_state = 0;
2093 if (ast_strlen_zero(agent)) {
2094 astman_send_error(s, m, "No agent specified");
2098 if (ast_strlen_zero(exten)) {
2099 astman_send_error(s, m, "No extension specified");
2103 ast_mutex_lock(&agentlock);
2106 if (strcmp(p->agent, agent) || p->pending) {
2111 login_state = 2; /* already logged in (and on the phone)*/
2114 ast_mutex_lock(&p->lock);
2115 login_state = 1; /* Successful Login */
2116 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
2118 if (ast_strlen_zero(context))
2119 snprintf(p->loginchan, sizeof(p->loginchan), "%s", exten);
2121 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
2123 if (wrapuptime_s && !ast_strlen_zero(wrapuptime_s)) {
2124 p->wrapuptime = atoi(wrapuptime_s);
2125 if (p->wrapuptime < 0)
2129 if (ast_true(ackcall_s))
2134 if (p->loginstart == 0)
2135 time(&p->loginstart);
2136 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
2138 "Loginchan: %s\r\n",
2139 p->agent, p->loginchan);
2140 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
2141 if (option_verbose > 1)
2142 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
2143 ast_device_state_changed("Agent/%s", p->agent);
2144 ast_mutex_unlock(&p->lock);
2147 ast_mutex_unlock(&agentlock);
2149 if (login_state == 1)
2150 astman_send_ack(s, m, "Agent logged in");
2151 else if (login_state == 0)
2152 astman_send_error(s, m, "No such agent");
2153 else if (login_state == 2)
2154 astman_send_error(s, m, "Agent already logged in");
2158 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2160 int exitifnoagentid = 0;
2162 int changeoutgoing = 0;
2164 char agent[AST_MAX_AGENT], *tmp;
2167 if (strchr(data, 'd'))
2168 exitifnoagentid = 1;
2169 if (strchr(data, 'n'))
2171 if (strchr(data, 'c'))
2174 if (chan->cid.cid_num) {
2175 char agentvar[AST_MAX_BUF];
2176 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2177 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2178 struct agent_pvt *p = agents;
2179 ast_copy_string(agent, tmp, sizeof(agent));
2180 ast_mutex_lock(&agentlock);
2182 if (!strcasecmp(p->agent, tmp)) {
2183 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2184 __agent_start_monitoring(chan, p, 1);
2189 ast_mutex_unlock(&agentlock);
2194 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);
2199 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");
2201 /* check if there is n + 101 priority */
2203 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2204 chan->priority+=100;
2205 if (option_verbose > 2)
2206 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2208 else if (exitifnoagentid)
2214 /* Dump AgentCallbackLogin agents to the database for persistence
2217 static void dump_agents(void)
2219 struct agent_pvt *cur_agent = NULL;
2222 for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2223 if (cur_agent->chan)
2226 if (!ast_strlen_zero(cur_agent->loginchan)) {
2227 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2228 if (ast_db_put(pa_family, cur_agent->agent, buf))
2229 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2230 else if (option_debug)
2231 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2233 /* Delete - no agent or there is an error */
2234 ast_db_del(pa_family, cur_agent->agent);
2240 * Reload the persistent agents from astdb.
2242 static void reload_agents(void)
2245 struct ast_db_entry *db_tree;
2246 struct ast_db_entry *entry;
2247 struct agent_pvt *cur_agent;
2248 char agent_data[256];
2251 char *agent_callerid;
2253 db_tree = ast_db_gettree(pa_family, NULL);
2255 ast_mutex_lock(&agentlock);
2256 for (entry = db_tree; entry; entry = entry->next) {
2257 agent_num = entry->key + strlen(pa_family) + 2;
2260 ast_mutex_lock(&cur_agent->lock);
2261 if (strcmp(agent_num, cur_agent->agent) == 0)
2263 ast_mutex_unlock(&cur_agent->lock);
2264 cur_agent = cur_agent->next;
2267 ast_db_del(pa_family, agent_num);
2270 ast_mutex_unlock(&cur_agent->lock);
2271 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2273 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2275 agent_chan = strsep(&parse, ";");
2276 agent_callerid = strsep(&parse, ";");
2277 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2278 if (agent_callerid) {
2279 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2280 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2282 cur_agent->logincallerid[0] = '\0';
2283 if (cur_agent->loginstart == 0)
2284 time(&cur_agent->loginstart);
2285 ast_device_state_changed("Agent/%s", cur_agent->agent);
2288 ast_mutex_unlock(&agentlock);
2290 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2291 ast_db_freetree(db_tree);
2295 /*--- agent_devicestate: Part of PBX channel interface ---*/
2296 static int agent_devicestate(void *data)
2298 struct agent_pvt *p;
2300 ast_group_t groupmatch;
2303 int res = AST_DEVICE_INVALID;
2306 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2307 groupmatch = (1 << groupoff);
2308 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2309 groupmatch = (1 << groupoff);
2315 /* Check actual logged in agents first */
2316 ast_mutex_lock(&agentlock);
2319 ast_mutex_lock(&p->lock);
2320 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2322 if (res != AST_DEVICE_INUSE)
2323 res = AST_DEVICE_BUSY;
2325 if (res == AST_DEVICE_BUSY)
2326 res = AST_DEVICE_INUSE;
2327 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2328 if (res == AST_DEVICE_INVALID)
2329 res = AST_DEVICE_UNKNOWN;
2330 } else if (res == AST_DEVICE_INVALID)
2331 res = AST_DEVICE_UNAVAILABLE;
2333 if (!strcmp(data, p->agent)) {
2334 ast_mutex_unlock(&p->lock);
2338 ast_mutex_unlock(&p->lock);
2341 ast_mutex_unlock(&agentlock);
2346 * Initialize the Agents module.
2347 * This funcion is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
2349 * @returns int Always 0.
2353 /* Make sure we can register our agent channel type */
2354 if (ast_channel_register(&agent_tech)) {
2355 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2358 /* Dialplan applications */
2359 ast_register_application(app, login_exec, synopsis, descrip);
2360 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2361 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2362 /* Manager commands */
2363 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2364 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2365 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
2366 /* CLI Application */
2367 ast_cli_register(&cli_show_agents);
2368 ast_cli_register(&cli_agent_logoff);
2369 /* Read in the config */
2370 read_agent_config();
2371 if (persistent_agents)
2378 read_agent_config();
2379 if (persistent_agents)
2386 struct agent_pvt *p;
2387 /* First, take us out of the channel loop */
2388 /* Unregister CLI application */
2389 ast_cli_unregister(&cli_show_agents);
2390 ast_cli_unregister(&cli_agent_logoff);
2391 /* Unregister dialplan applications */
2392 ast_unregister_application(app);
2393 ast_unregister_application(app2);
2394 ast_unregister_application(app3);
2395 /* Unregister manager command */
2396 ast_manager_unregister("Agents");
2397 ast_manager_unregister("AgentLogoff");
2398 ast_manager_unregister("AgentCallbackLogin");
2399 /* Unregister channel */
2400 ast_channel_unregister(&agent_tech);
2401 if (!ast_mutex_lock(&agentlock)) {
2402 /* Hangup all interfaces if they have an owner */
2406 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2410 ast_mutex_unlock(&agentlock);
2412 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2425 return ASTERISK_GPL_KEY;
2430 return (char *) desc;