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
15 * @brief This file is the implementation of Agents modules.
16 * It is a dynamic module that is loaded by Asterisk. At load time, load_module is run.
23 #include <sys/socket.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
29 #include <sys/signal.h>
33 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
35 #include "asterisk/lock.h"
36 #include "asterisk/channel.h"
37 #include "asterisk/config.h"
38 #include "asterisk/logger.h"
39 #include "asterisk/module.h"
40 #include "asterisk/pbx.h"
41 #include "asterisk/options.h"
42 #include "asterisk/lock.h"
43 #include "asterisk/sched.h"
44 #include "asterisk/io.h"
45 #include "asterisk/rtp.h"
46 #include "asterisk/acl.h"
47 #include "asterisk/callerid.h"
48 #include "asterisk/file.h"
49 #include "asterisk/cli.h"
50 #include "asterisk/app.h"
51 #include "asterisk/musiconhold.h"
52 #include "asterisk/manager.h"
53 #include "asterisk/features.h"
54 #include "asterisk/utils.h"
55 #include "asterisk/causes.h"
56 #include "asterisk/astdb.h"
57 #include "asterisk/devicestate.h"
59 static const char desc[] = "Agent Proxy Channel";
60 static const char channeltype[] = "Agent";
61 static const char tdesc[] = "Call Agent Proxy Channel";
62 static const char config[] = "agents.conf";
64 static const char app[] = "AgentLogin";
65 static const char app2[] = "AgentCallbackLogin";
66 static const char app3[] = "AgentMonitorOutgoing";
68 static const char synopsis[] = "Call agent login";
69 static const char synopsis2[] = "Call agent callback login";
70 static const char synopsis3[] = "Record agent's outgoing call";
72 static const char descrip[] =
73 " AgentLogin([AgentNo][|options]):\n"
74 "Asks the agent to login to the system. Always returns -1. While\n"
75 "logged in, the agent can receive calls and will hear a 'beep'\n"
76 "when a new call comes in. The agent can dump the call by pressing\n"
78 "The option string may contain zero or more of the following characters:\n"
79 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
81 static const char descrip2[] =
82 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
83 "Asks the agent to login to the system with callback.\n"
84 "The agent's callback extension is called (optionally with the specified\n"
86 "The option string may contain zero or more of the following characters:\n"
87 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
89 static const char descrip3[] =
90 " AgentMonitorOutgoing([options]):\n"
91 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
92 "comparision of the callerid of the current interface and the global variable \n"
93 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
94 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
95 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
97 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
98 "the agentid are not specified it'll look for n+101 priority.\n"
100 " 'd' - make the app return -1 if there is an error condition and there is\n"
101 " no extension n+101\n"
102 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
103 " 'n' - don't generate the warnings when there is no callerid or the\n"
104 " agentid is not known.\n"
105 " It's handy if you want to have one context for agent and non-agent calls.\n";
107 static const char mandescr_agents[] =
108 "Description: Will list info about all possible agents.\n"
111 static const char mandescr_agent_logoff[] =
112 "Description: Sets an agent as no longer logged in.\n"
113 "Variables: (Names marked with * are required)\n"
114 " *Agent: Agent ID of the agent to log off\n"
115 " Soft: Set to 'true' to not hangup existing calls\n";
117 static const char mandescr_agent_callback_login[] =
118 "Description: Sets an agent as logged in with callback.\n"
119 "Variables: (Names marked with * are required)\n"
120 " *Agent: Agent ID of the agent to login\n"
121 " *Extension: Extension to use for callback\n"
122 " Context: Context to use for callback\n"
123 " AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
124 " WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
126 static char moh[80] = "default";
128 #define AST_MAX_AGENT 80 /**< Agent ID or Password max length */
129 #define AST_MAX_BUF 256
130 #define AST_MAX_FILENAME_LEN 256
132 /** Persistent Agents astdb family */
133 static const char pa_family[] = "/Agents";
134 /** The maximum lengh of each persistent member agent database entry */
135 #define PA_MAX_LEN 2048
136 /** queues.conf [general] option */
137 static int persistent_agents = 0;
138 static void dump_agents(void);
140 static ast_group_t group;
141 static int autologoff;
142 static int wrapuptime;
145 static int maxlogintries = 3;
146 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
148 static int usecnt =0;
149 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
151 /* Protect the interface list (of pvt's) */
152 AST_MUTEX_DEFINE_STATIC(agentlock);
154 static int recordagentcalls = 0;
155 static char recordformat[AST_MAX_BUF] = "";
156 static char recordformatext[AST_MAX_BUF] = "";
157 static int createlink = 0;
158 static char urlprefix[AST_MAX_BUF] = "";
159 static char savecallsin[AST_MAX_BUF] = "";
160 static int updatecdr = 0;
161 static char beep[AST_MAX_BUF] = "beep";
163 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
166 * Structure representing an agent.
169 ast_mutex_t lock; /**< Channel private lock */
170 int dead; /**< Poised for destruction? */
171 int pending; /**< Not a real agent -- just pending a match */
172 int abouttograb; /**< About to grab */
173 int autologoff; /**< Auto timeout time */
174 int ackcall; /**< ackcall */
175 time_t loginstart; /**< When agent first logged in (0 when logged off) */
176 time_t start; /**< When call started */
177 struct timeval lastdisc; /**< When last disconnected */
178 int wrapuptime; /**< Wrapup time in ms */
179 ast_group_t group; /**< Group memberships */
180 int acknowledged; /**< Acknowledged */
181 char moh[80]; /**< Which music on hold */
182 char agent[AST_MAX_AGENT]; /**< Agent ID */
183 char password[AST_MAX_AGENT]; /**< Password for Agent login */
184 char name[AST_MAX_AGENT];
185 ast_mutex_t app_lock; /**< Synchronization between owning applications */
186 volatile pthread_t owning_app; /**< Owning application thread id */
187 volatile int app_sleep_cond; /**< Sleep condition for the login app */
188 struct ast_channel *owner; /**< Agent */
189 char loginchan[80]; /**< channel they logged in from */
190 char logincallerid[80]; /**< Caller ID they had when they logged in */
191 struct ast_channel *chan; /**< Channel we use */
192 struct agent_pvt *next; /**< Next Agent in the linked list. */
195 static struct agent_pvt *agents = NULL; /**< Holds the list of agents (loaded form agents.conf). */
197 #define CHECK_FORMATS(ast, p) do { \
199 if (ast->nativeformats != p->chan->nativeformats) { \
200 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
201 /* Native formats changed, reset things */ \
202 ast->nativeformats = p->chan->nativeformats; \
203 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
204 ast_set_read_format(ast, ast->readformat); \
205 ast_set_write_format(ast, ast->writeformat); \
207 if (p->chan->readformat != ast->rawreadformat) \
208 ast_set_read_format(p->chan, ast->rawreadformat); \
209 if (p->chan->writeformat != ast->rawwriteformat) \
210 ast_set_write_format(p->chan, ast->rawwriteformat); \
214 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
215 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
216 totally impractical combinations XXX */
218 #define CLEANUP(ast, p) do { \
221 for (x=0;x<AST_MAX_FDS;x++) {\
222 if (x != AST_MAX_FDS - 2) \
223 ast->fds[x] = p->chan->fds[x]; \
225 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
229 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
230 static int agent_devicestate(void *data);
231 static int agent_digit(struct ast_channel *ast, char digit);
232 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
233 static int agent_hangup(struct ast_channel *ast);
234 static int agent_answer(struct ast_channel *ast);
235 static struct ast_frame *agent_read(struct ast_channel *ast);
236 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
237 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
238 static int agent_indicate(struct ast_channel *ast, int condition);
239 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
240 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
242 static const struct ast_channel_tech agent_tech = {
244 .description = tdesc,
246 .requester = agent_request,
247 .devicestate = agent_devicestate,
248 .send_digit = agent_digit,
250 .hangup = agent_hangup,
251 .answer = agent_answer,
253 .write = agent_write,
254 .send_html = agent_sendhtml,
255 .exception = agent_read,
256 .indicate = agent_indicate,
257 .fixup = agent_fixup,
258 .bridged_channel = agent_bridgedchannel,
262 * Unlink (that is, take outside of the linked list) an agent.
264 * @param agent Agent to be unlinked.
266 static void agent_unlink(struct agent_pvt *agent)
268 struct agent_pvt *p, *prev;
271 // Iterate over all agents looking for the one.
274 // Once it wal found, check if it is the first one.
276 // If it is not, tell the previous agent that the next one is the next one of the current (jumping the current).
277 prev->next = agent->next;
279 // If it is the first one, just change the general pointer to point to the second one.
280 agents = agent->next;
290 * Adds an agent to the global list of agents.
292 * @param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
293 * @param pending If it is pending or not.
294 * @return The just created agent.
295 * @sa agent_pvt, agents.
297 static struct agent_pvt *add_agent(char *agent, int pending)
302 char *password = NULL;
305 struct agent_pvt *p, *prev;
307 args = ast_strdupa(agent);
309 // Extract username (agt), password and name from agent (args).
310 if ((argc = ast_separate_app_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) {
314 while (*password && *password < 33) password++;
318 while (*name && *name < 33) name++;
321 ast_log(LOG_WARNING, "A blank agent line!\n");
324 // Are we searching for the agent here ? to see if it exists already ?
328 if (!pending && !strcmp(p->agent, agt))
335 p = malloc(sizeof(struct agent_pvt));
337 memset(p, 0, sizeof(struct agent_pvt));
338 ast_copy_string(p->agent, agt, sizeof(p->agent));
339 ast_mutex_init(&p->lock);
340 ast_mutex_init(&p->app_lock);
341 p->owning_app = (pthread_t) -1;
342 p->app_sleep_cond = 1;
344 p->pending = pending;
356 ast_copy_string(p->password, password ? password : "", sizeof(p->password));
357 ast_copy_string(p->name, name ? name : "", sizeof(p->name));
358 ast_copy_string(p->moh, moh, sizeof(p->moh));
359 p->ackcall = ackcall;
360 p->autologoff = autologoff;
362 /* If someone reduces the wrapuptime and reloads, we want it
363 * to change the wrapuptime immediately on all calls */
364 if (p->wrapuptime > wrapuptime) {
365 struct timeval now = ast_tvnow();
366 /* XXX check what is this exactly */
368 /* We won't be pedantic and check the tv_usec val */
369 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
370 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
371 p->lastdisc.tv_usec = now.tv_usec;
374 p->wrapuptime = wrapuptime;
384 * Deletes an agent after doing some clean up.
385 * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
386 * @param p Agent to be deleted.
389 static int agent_cleanup(struct agent_pvt *p)
391 struct ast_channel *chan = p->owner;
393 chan->tech_pvt = NULL;
394 p->app_sleep_cond = 1;
395 /* Release ownership of the agent to other threads (presumably running the login app). */
396 ast_mutex_unlock(&p->app_lock);
398 ast_channel_free(chan);
400 ast_mutex_destroy(&p->lock);
401 ast_mutex_destroy(&p->app_lock);
407 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
409 static int agent_answer(struct ast_channel *ast)
411 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
415 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
417 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
418 char filename[AST_MAX_BUF];
423 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
424 /* substitute . for - */
425 if ((pointer = strchr(filename, '.')))
427 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
428 ast_monitor_start(ast, recordformat, tmp, needlock);
429 ast_monitor_setjoinfiles(ast, 1);
430 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
432 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
435 ast->cdr = ast_cdr_alloc();
436 ast_cdr_setuserfield(ast, tmp2);
439 ast_log(LOG_ERROR, "Recording already started on that call.\n");
443 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
445 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
448 static struct ast_frame *agent_read(struct ast_channel *ast)
450 struct agent_pvt *p = ast->tech_pvt;
451 struct ast_frame *f = NULL;
452 static struct ast_frame null_frame = { AST_FRAME_NULL, };
453 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
454 ast_mutex_lock(&p->lock);
455 CHECK_FORMATS(ast, p);
457 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
458 if (ast->fdno == AST_MAX_FDS - 3)
459 p->chan->fdno = AST_MAX_FDS - 2;
461 p->chan->fdno = ast->fdno;
462 f = ast_read(p->chan);
466 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
468 p->chan->_bridge = NULL;
469 /* Note that we don't hangup if it's not a callback because Asterisk will do it
470 for us when the PBX instance that called login finishes */
471 if (!ast_strlen_zero(p->loginchan)) {
473 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
475 if (p->wrapuptime && p->acknowledged)
476 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
482 /* if acknowledgement is not required, and the channel is up, we may have missed
483 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
484 if (!p->ackcall && !p->acknowledged && p->chan->_state == AST_STATE_UP)
486 switch (f->frametype) {
487 case AST_FRAME_CONTROL:
488 if (f->subclass == AST_CONTROL_ANSWER) {
490 if (option_verbose > 2)
491 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
492 /* Don't pass answer along */
497 /* Use the builtin answer frame for the
498 recording start check below. */
505 if (!p->acknowledged && (f->subclass == '#')) {
506 if (option_verbose > 2)
507 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
511 } else if (f->subclass == '*') {
512 /* terminates call */
517 case AST_FRAME_VOICE:
518 /* don't pass voice until the call is acknowledged */
519 if (!p->acknowledged) {
528 if (p->chan && !p->chan->_bridge) {
529 if (strcasecmp(p->chan->type, "Local")) {
530 p->chan->_bridge = ast;
532 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
535 ast_mutex_unlock(&p->lock);
536 if (recordagentcalls && f == &answer_frame)
537 agent_start_monitoring(ast,0);
541 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
543 struct agent_pvt *p = ast->tech_pvt;
545 ast_mutex_lock(&p->lock);
547 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
548 ast_mutex_unlock(&p->lock);
552 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
554 struct agent_pvt *p = ast->tech_pvt;
556 CHECK_FORMATS(ast, p);
557 ast_mutex_lock(&p->lock);
559 if ((f->frametype != AST_FRAME_VOICE) ||
560 (f->subclass == p->chan->writeformat)) {
561 res = ast_write(p->chan, f);
563 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
569 ast_mutex_unlock(&p->lock);
573 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
575 struct agent_pvt *p = newchan->tech_pvt;
576 ast_mutex_lock(&p->lock);
577 if (p->owner != oldchan) {
578 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
579 ast_mutex_unlock(&p->lock);
583 ast_mutex_unlock(&p->lock);
587 static int agent_indicate(struct ast_channel *ast, int condition)
589 struct agent_pvt *p = ast->tech_pvt;
591 ast_mutex_lock(&p->lock);
593 res = ast_indicate(p->chan, condition);
596 ast_mutex_unlock(&p->lock);
600 static int agent_digit(struct ast_channel *ast, char digit)
602 struct agent_pvt *p = ast->tech_pvt;
604 ast_mutex_lock(&p->lock);
606 res = p->chan->tech->send_digit(p->chan, digit);
609 ast_mutex_unlock(&p->lock);
613 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
615 struct agent_pvt *p = ast->tech_pvt;
618 ast_mutex_lock(&p->lock);
622 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
623 newstate = AST_STATE_DIALING;
626 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
629 ast_mutex_unlock(&p->lock);
631 ast_setstate(ast, newstate);
633 } else if (!ast_strlen_zero(p->loginchan)) {
635 /* Call on this agent */
636 if (option_verbose > 2)
637 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
638 if (p->chan->cid.cid_num)
639 free(p->chan->cid.cid_num);
640 if (ast->cid.cid_num)
641 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
643 p->chan->cid.cid_num = NULL;
644 if (p->chan->cid.cid_name)
645 free(p->chan->cid.cid_name);
646 if (ast->cid.cid_name)
647 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
649 p->chan->cid.cid_name = NULL;
650 ast_channel_inherit_variables(ast, p->chan);
651 res = ast_call(p->chan, p->loginchan, 0);
653 ast_mutex_unlock(&p->lock);
656 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
657 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
658 res = ast_streamfile(p->chan, beep, p->chan->language);
659 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
661 res = ast_waitstream(p->chan, "");
662 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
665 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
666 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
668 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
675 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
676 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
678 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
682 /* Call is immediately up, or might need ack */
684 newstate = AST_STATE_RINGING;
686 newstate = AST_STATE_UP;
687 if (recordagentcalls)
688 agent_start_monitoring(ast,0);
694 ast_mutex_unlock(&p->lock);
696 ast_setstate(ast, newstate);
700 /* store/clear the global variable that stores agentid based on the callerid */
701 static void set_agentbycallerid(const char *callerid, const char *agent)
703 char buf[AST_MAX_BUF];
705 /* if there is no Caller ID, nothing to do */
706 if (!callerid || ast_strlen_zero(callerid))
709 snprintf(buf, sizeof(buf), "%s_%s",GETAGENTBYCALLERID, callerid);
710 pbx_builtin_setvar_helper(NULL, buf, agent);
713 static int agent_hangup(struct ast_channel *ast)
715 struct agent_pvt *p = ast->tech_pvt;
717 ast_mutex_lock(&p->lock);
719 ast->tech_pvt = NULL;
720 p->app_sleep_cond = 1;
723 /* if they really are hung up then set start to 0 so the test
724 * later if we're called on an already downed channel
725 * doesn't cause an agent to be logged out like when
726 * agent_request() is followed immediately by agent_hangup()
727 * as in apps/app_chanisavail.c:chanavail_exec()
730 ast_mutex_lock(&usecnt_lock);
732 ast_mutex_unlock(&usecnt_lock);
734 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
735 if (p->start && (ast->_state != AST_STATE_UP)) {
736 howlong = time(NULL) - p->start;
738 } else if (ast->_state == AST_STATE_RESERVED) {
743 p->chan->_bridge = NULL;
744 /* If they're dead, go ahead and hang up on the agent now */
745 if (!ast_strlen_zero(p->loginchan)) {
746 /* Store last disconnect time */
747 if (p->wrapuptime && p->acknowledged)
748 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
750 p->lastdisc = ast_tv(0,0);
752 /* Recognize the hangup and pass it along immediately */
756 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
757 if (howlong && p->autologoff && (howlong > p->autologoff)) {
758 char agent[AST_MAX_AGENT] = "";
759 long logintime = time(NULL) - p->loginstart;
761 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
762 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
766 "Reason: Autologoff\r\n"
768 p->agent, p->loginchan, logintime, ast->uniqueid);
769 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
770 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
771 set_agentbycallerid(p->logincallerid, NULL);
772 p->loginchan[0] = '\0';
773 p->logincallerid[0] = '\0';
775 } else if (p->dead) {
776 ast_mutex_lock(&p->chan->lock);
777 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
778 ast_mutex_unlock(&p->chan->lock);
780 ast_mutex_lock(&p->chan->lock);
781 ast_moh_start(p->chan, p->moh);
782 ast_mutex_unlock(&p->chan->lock);
785 ast_mutex_unlock(&p->lock);
786 ast_device_state_changed("Agent/%s", p->agent);
789 ast_mutex_lock(&agentlock);
791 ast_mutex_unlock(&agentlock);
793 if (p->abouttograb) {
794 /* Let the "about to grab" thread know this isn't valid anymore, and let it
797 } else if (p->dead) {
798 ast_mutex_destroy(&p->lock);
799 ast_mutex_destroy(&p->app_lock);
803 /* Not dead -- check availability now */
804 ast_mutex_lock(&p->lock);
805 /* Store last disconnect time */
806 p->lastdisc = ast_tvnow();
807 ast_mutex_unlock(&p->lock);
809 /* Release ownership of the agent to other threads (presumably running the login app). */
810 ast_mutex_unlock(&p->app_lock);
815 static int agent_cont_sleep( void *data )
820 p = (struct agent_pvt *)data;
822 ast_mutex_lock(&p->lock);
823 res = p->app_sleep_cond;
824 if (p->lastdisc.tv_sec) {
825 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime)
828 ast_mutex_unlock(&p->lock);
831 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
836 static int agent_ack_sleep( void *data )
843 /* Wait a second and look for something */
845 p = (struct agent_pvt *)data;
848 to = ast_waitfor(p->chan, to);
857 f = ast_read(p->chan);
862 if (f->frametype == AST_FRAME_DTMF)
867 ast_mutex_lock(&p->lock);
868 if (!p->app_sleep_cond) {
869 ast_mutex_unlock(&p->lock);
872 } else if (res == '#') {
873 ast_mutex_unlock(&p->lock);
877 ast_mutex_unlock(&p->lock);
885 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
888 struct ast_channel *ret=NULL;
891 p = bridge->tech_pvt;
893 ret = bridge->_bridge;
894 else if (chan == bridge->_bridge)
897 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
901 /*--- agent_new: Create new agent channel ---*/
902 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
904 struct ast_channel *tmp;
905 struct ast_frame null_frame = { AST_FRAME_NULL };
908 ast_log(LOG_WARNING, "No channel? :(\n");
912 tmp = ast_channel_alloc(0);
914 tmp->tech = &agent_tech;
916 tmp->nativeformats = p->chan->nativeformats;
917 tmp->writeformat = p->chan->writeformat;
918 tmp->rawwriteformat = p->chan->writeformat;
919 tmp->readformat = p->chan->readformat;
920 tmp->rawreadformat = p->chan->readformat;
921 ast_copy_string(tmp->language, p->chan->language, sizeof(tmp->language));
922 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
923 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
925 tmp->nativeformats = AST_FORMAT_SLINEAR;
926 tmp->writeformat = AST_FORMAT_SLINEAR;
927 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
928 tmp->readformat = AST_FORMAT_SLINEAR;
929 tmp->rawreadformat = AST_FORMAT_SLINEAR;
932 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
934 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
935 tmp->type = channeltype;
936 /* Safe, agentlock already held */
937 ast_setstate(tmp, state);
940 ast_mutex_lock(&usecnt_lock);
942 ast_mutex_unlock(&usecnt_lock);
943 ast_update_use_count();
945 /* Wake up and wait for other applications (by definition the login app)
946 * to release this channel). Takes ownership of the agent channel
947 * to this thread only.
948 * For signalling the other thread, ast_queue_frame is used until we
949 * can safely use signals for this purpose. The pselect() needs to be
950 * implemented in the kernel for this.
952 p->app_sleep_cond = 0;
953 if( ast_mutex_trylock(&p->app_lock) )
956 ast_queue_frame(p->chan, &null_frame);
957 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
958 ast_mutex_lock(&p->app_lock);
959 ast_mutex_lock(&p->lock);
963 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
965 tmp->tech_pvt = NULL;
966 p->app_sleep_cond = 1;
967 ast_channel_free( tmp );
968 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
969 ast_mutex_unlock(&p->app_lock);
973 p->owning_app = pthread_self();
974 /* After the above step, there should not be any blockers. */
976 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
977 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
980 ast_moh_stop(p->chan);
983 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
989 * Read configuration data. The file named agents.conf.
991 * @returns Always 0, or so it seems.
993 static int read_agent_config(void)
995 struct ast_config *cfg;
996 struct ast_variable *v;
997 struct agent_pvt *p, *pl, *pn;
1004 cfg = ast_config_load(config);
1006 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1009 ast_mutex_lock(&agentlock);
1015 strcpy(moh, "default");
1016 /* set the default recording values */
1017 recordagentcalls = 0;
1019 strcpy(recordformat, "wav");
1020 strcpy(recordformatext, "wav");
1021 urlprefix[0] = '\0';
1022 savecallsin[0] = '\0';
1024 /* Read in [general] section for persistance */
1025 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1026 persistent_agents = ast_true(general_val);
1028 /* Read in the [agents] section */
1029 v = ast_variable_browse(cfg, "agents");
1031 /* Create the interface list */
1032 if (!strcasecmp(v->name, "agent")) {
1033 add_agent(v->value, 0);
1034 } else if (!strcasecmp(v->name, "group")) {
1035 group = ast_get_group(v->value);
1036 } else if (!strcasecmp(v->name, "autologoff")) {
1037 autologoff = atoi(v->value);
1040 } else if (!strcasecmp(v->name, "ackcall")) {
1041 if (!strcasecmp(v->value, "always"))
1043 else if (ast_true(v->value))
1047 } else if (!strcasecmp(v->name, "wrapuptime")) {
1048 wrapuptime = atoi(v->value);
1051 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1052 maxlogintries = atoi(v->value);
1053 if (maxlogintries < 0)
1055 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1056 strcpy(agentgoodbye,v->value);
1057 } else if (!strcasecmp(v->name, "musiconhold")) {
1058 ast_copy_string(moh, v->value, sizeof(moh));
1059 } else if (!strcasecmp(v->name, "updatecdr")) {
1060 if (ast_true(v->value))
1064 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1065 recordagentcalls = ast_true(v->value);
1066 } else if (!strcasecmp(v->name, "createlink")) {
1067 createlink = ast_true(v->value);
1068 } else if (!strcasecmp(v->name, "recordformat")) {
1069 ast_copy_string(recordformat, v->value, sizeof(recordformat));
1070 if (!strcasecmp(v->value, "wav49"))
1071 strcpy(recordformatext, "WAV");
1073 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1074 } else if (!strcasecmp(v->name, "urlprefix")) {
1075 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1076 if (urlprefix[strlen(urlprefix) - 1] != '/')
1077 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1078 } else if (!strcasecmp(v->name, "savecallsin")) {
1079 if (v->value[0] == '/')
1080 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1082 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1083 if (savecallsin[strlen(savecallsin) - 1] != '/')
1084 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1085 } else if (!strcasecmp(v->name, "custom_beep")) {
1086 ast_copy_string(beep, v->value, sizeof(beep));
1100 /* Destroy if appropriate */
1103 ast_mutex_destroy(&p->lock);
1104 ast_mutex_destroy(&p->app_lock);
1107 /* Cause them to hang up */
1108 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1115 ast_mutex_unlock(&agentlock);
1116 ast_config_destroy(cfg);
1120 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1122 struct ast_channel *chan=NULL, *parent=NULL;
1123 struct agent_pvt *p;
1127 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1129 ast_mutex_lock(&agentlock);
1132 if (p == newlyavailable) {
1136 ast_mutex_lock(&p->lock);
1137 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1139 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1140 /* We found a pending call, time to merge */
1141 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1144 ast_mutex_unlock(&p->lock);
1147 ast_mutex_unlock(&p->lock);
1151 ast_mutex_unlock(&agentlock);
1152 if (parent && chan) {
1153 if (newlyavailable->ackcall > 1) {
1154 /* Don't do beep here */
1157 if (option_debug > 2)
1158 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1159 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1160 if (option_debug > 2)
1161 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1163 res = ast_waitstream(newlyavailable->chan, "");
1164 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1168 /* Note -- parent may have disappeared */
1169 if (p->abouttograb) {
1170 newlyavailable->acknowledged = 1;
1171 /* Safe -- agent lock already held */
1172 ast_setstate(parent, AST_STATE_UP);
1173 ast_setstate(chan, AST_STATE_UP);
1174 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1175 /* Go ahead and mark the channel as a zombie so that masquerade will
1176 destroy it for us, and we need not call ast_hangup */
1177 ast_mutex_lock(&parent->lock);
1178 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1179 ast_channel_masquerade(parent, chan);
1180 ast_mutex_unlock(&parent->lock);
1184 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1185 agent_cleanup(newlyavailable);
1189 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1190 agent_cleanup(newlyavailable);
1196 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1198 struct agent_pvt *p;
1201 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1203 ast_mutex_lock(&agentlock);
1206 if (p == newlyavailable) {
1210 ast_mutex_lock(&p->lock);
1211 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1213 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1214 ast_mutex_unlock(&p->lock);
1217 ast_mutex_unlock(&p->lock);
1221 ast_mutex_unlock(&agentlock);
1223 ast_mutex_unlock(&newlyavailable->lock);
1224 if (option_debug > 2)
1225 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1226 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1227 if (option_debug > 2)
1228 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1230 res = ast_waitstream(newlyavailable->chan, "");
1232 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1234 ast_mutex_lock(&newlyavailable->lock);
1239 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1240 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1242 struct agent_pvt *p;
1243 struct ast_channel *chan = NULL;
1245 ast_group_t groupmatch;
1252 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1253 groupmatch = (1 << groupoff);
1254 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1255 groupmatch = (1 << groupoff);
1261 /* Check actual logged in agents first */
1262 ast_mutex_lock(&agentlock);
1265 ast_mutex_lock(&p->lock);
1266 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1267 ast_strlen_zero(p->loginchan)) {
1270 if (!p->lastdisc.tv_sec) {
1271 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1272 if (!p->owner && p->chan) {
1274 chan = agent_new(p, AST_STATE_DOWN);
1277 ast_mutex_unlock(&p->lock);
1282 ast_mutex_unlock(&p->lock);
1288 ast_mutex_lock(&p->lock);
1289 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1290 if (p->chan || !ast_strlen_zero(p->loginchan))
1294 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1296 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1297 p->lastdisc = ast_tv(0, 0);
1298 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1299 if (!p->owner && p->chan) {
1300 /* Could still get a fixed agent */
1301 chan = agent_new(p, AST_STATE_DOWN);
1302 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1303 /* Adjustable agent */
1304 p->chan = ast_request("Local", format, p->loginchan, cause);
1306 chan = agent_new(p, AST_STATE_DOWN);
1309 ast_mutex_unlock(&p->lock);
1314 ast_mutex_unlock(&p->lock);
1319 if (!chan && waitforagent) {
1320 /* No agent available -- but we're requesting to wait for one.
1321 Allocate a place holder */
1324 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1325 p = add_agent(data, 1);
1326 p->group = groupmatch;
1327 chan = agent_new(p, AST_STATE_DOWN);
1329 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1332 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1335 *cause = AST_CAUSE_BUSY;
1337 *cause = AST_CAUSE_UNREGISTERED;
1338 ast_mutex_unlock(&agentlock);
1342 static int powerof(unsigned int v)
1345 for (x=0;x<32;x++) {
1346 if (v & (1 << x)) return x;
1352 * Lists agents and their status to the Manager API.
1353 * It is registered on load_module() and it gets called by the manager backend.
1357 * @sa action_agent_logoff(), action_agent_callback_login(), load_module().
1359 static int action_agents(struct mansession *s, struct message *m)
1361 char *id = astman_get_header(m,"ActionID");
1362 char idText[256] = "";
1363 struct agent_pvt *p;
1364 char *username = NULL;
1365 char *loginChan = NULL;
1366 char *talkingtoChan = NULL;
1367 char *status = NULL;
1369 if (id && !ast_strlen_zero(id))
1370 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1371 astman_send_ack(s, m, "Agents will follow");
1372 ast_mutex_lock(&agentlock);
1374 ast_mutex_lock(&s->lock);
1376 ast_mutex_lock(&p->lock);
1379 AGENT_LOGGEDOFF - Agent isn't logged in
1380 AGENT_IDLE - Agent is logged in, and waiting for call
1381 AGENT_ONCALL - Agent is logged in, and on a call
1382 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1384 if(!ast_strlen_zero(p->name)) {
1390 /* Set a default status. It 'should' get changed. */
1391 status = "AGENT_UNKNOWN";
1394 loginChan = p->loginchan;
1395 if(p->owner && p->owner->_bridge) {
1396 talkingtoChan = p->chan->cid.cid_num;
1397 status = "AGENT_ONCALL";
1399 talkingtoChan = "n/a";
1400 status = "AGENT_IDLE";
1402 } else if(!ast_strlen_zero(p->loginchan)) {
1403 loginChan = p->loginchan;
1404 talkingtoChan = "n/a";
1405 status = "AGENT_IDLE";
1406 if(p->acknowledged) {
1407 sprintf(loginChan, " %s (Confirmed)", loginChan);
1411 talkingtoChan = "n/a";
1412 status = "AGENT_LOGGEDOFF";
1415 ast_cli(s->fd, "Event: Agents\r\n"
1419 "LoggedInChan: %s\r\n"
1420 "LoggedInTime: %ld\r\n"
1424 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan,idText);
1425 ast_mutex_unlock(&p->lock);
1428 ast_mutex_unlock(&agentlock);
1429 ast_cli(s->fd, "Event: AgentsComplete\r\n"
1432 ast_mutex_unlock(&s->lock);
1437 static int agent_logoff(char *agent, int soft)
1439 struct agent_pvt *p;
1441 int ret = -1; /* Return -1 if no agent if found */
1443 for (p=agents; p; p=p->next) {
1444 if (!strcasecmp(p->agent, agent)) {
1447 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1450 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1453 ret = 0; /* found an agent => return 0 */
1454 logintime = time(NULL) - p->loginstart;
1457 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1460 "Logintime: %ld\r\n",
1461 p->agent, p->loginchan, logintime);
1462 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1463 set_agentbycallerid(p->logincallerid, NULL);
1464 p->loginchan[0] = '\0';
1465 p->logincallerid[0] = '\0';
1466 ast_device_state_changed("Agent/%s", p->agent);
1467 if (persistent_agents)
1476 static int agent_logoff_cmd(int fd, int argc, char **argv)
1481 if (argc < 3 || argc > 4)
1482 return RESULT_SHOWUSAGE;
1483 if (argc == 4 && strcasecmp(argv[3], "soft"))
1484 return RESULT_SHOWUSAGE;
1486 agent = argv[2] + 6;
1487 ret = agent_logoff(agent, argc == 4);
1489 ast_cli(fd, "Logging out %s\n", agent);
1491 return RESULT_SUCCESS;
1495 * Sets an agent as no longer logged in in the Manager API.
1496 * It is registered on load_module() and it gets called by the manager backend.
1500 * @sa action_agents(), action_agent_callback_login(), load_module().
1502 static int action_agent_logoff(struct mansession *s, struct message *m)
1504 char *agent = astman_get_header(m, "Agent");
1505 char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1507 int ret; /* return value of agent_logoff */
1509 if (!agent || ast_strlen_zero(agent)) {
1510 astman_send_error(s, m, "No agent specified");
1514 if (ast_true(soft_s))
1519 ret = agent_logoff(agent, soft);
1521 astman_send_ack(s, m, "Agent logged out");
1523 astman_send_error(s, m, "No such agent");
1528 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1530 struct agent_pvt *p;
1531 char name[AST_MAX_AGENT];
1535 for (p=agents; p; p=p->next) {
1536 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1537 if (!strncasecmp(word, name, strlen(word))) {
1538 if (++which > state) {
1539 return strdup(name);
1543 } else if (pos == 3 && state == 0) {
1544 return strdup("soft");
1550 * Show agents in cli.
1552 static int agents_show(int fd, int argc, char **argv)
1554 struct agent_pvt *p;
1555 char username[AST_MAX_BUF];
1556 char location[AST_MAX_BUF] = "";
1557 char talkingto[AST_MAX_BUF] = "";
1558 char moh[AST_MAX_BUF];
1559 int count_agents = 0; /* Number of agents configured */
1560 int online_agents = 0; /* Number of online agents */
1561 int offline_agents = 0; /* Number of offline agents */
1563 return RESULT_SHOWUSAGE;
1564 ast_mutex_lock(&agentlock);
1567 ast_mutex_lock(&p->lock);
1570 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1572 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1574 if (!ast_strlen_zero(p->name))
1575 snprintf(username, sizeof(username), "(%s) ", p->name);
1579 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1580 if (p->owner && ast_bridged_channel(p->owner)) {
1581 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1583 strcpy(talkingto, " is idle");
1586 } else if (!ast_strlen_zero(p->loginchan)) {
1587 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1588 talkingto[0] = '\0';
1590 if (p->acknowledged)
1591 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1593 strcpy(location, "not logged in");
1594 talkingto[0] = '\0';
1597 if (!ast_strlen_zero(p->moh))
1598 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1599 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1600 username, location, talkingto, moh);
1603 ast_mutex_unlock(&p->lock);
1606 ast_mutex_unlock(&agentlock);
1607 if ( !count_agents ) {
1608 ast_cli(fd, "No Agents are configured in %s\n",config);
1610 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1614 return RESULT_SUCCESS;
1617 static char show_agents_usage[] =
1618 "Usage: show agents\n"
1619 " Provides summary information on agents.\n";
1621 static char agent_logoff_usage[] =
1622 "Usage: agent logoff <channel> [soft]\n"
1623 " Sets an agent as no longer logged in.\n"
1624 " If 'soft' is specified, do not hangup existing calls.\n";
1626 static struct ast_cli_entry cli_show_agents = {
1627 { "show", "agents", NULL }, agents_show,
1628 "Show status of agents", show_agents_usage, NULL };
1630 static struct ast_cli_entry cli_agent_logoff = {
1631 { "agent", "logoff", NULL }, agent_logoff_cmd,
1632 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1634 STANDARD_LOCAL_USER;
1638 * Log in agent application.
1642 * @param callbackmode
1645 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1649 int max_login_tries = maxlogintries;
1650 struct agent_pvt *p;
1651 struct localuser *u;
1652 int login_state = 0;
1653 char user[AST_MAX_AGENT] = "";
1654 char pass[AST_MAX_AGENT];
1655 char agent[AST_MAX_AGENT] = "";
1656 char xpass[AST_MAX_AGENT] = "";
1659 char *opt_user = NULL;
1660 char *options = NULL;
1663 char *tmpoptions = NULL;
1664 char *context = NULL;
1666 int play_announcement = 1;
1667 char agent_goodbye[AST_MAX_FILENAME_LEN];
1668 int update_cdr = updatecdr;
1669 char *filename = "agent-loginok";
1671 strcpy(agent_goodbye, agentgoodbye);
1674 /* Parse the arguments XXX Check for failure XXX */
1675 ast_copy_string(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION);
1677 /* Set Channel Specific Login Overrides */
1678 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1679 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1680 if (max_login_tries < 0)
1681 max_login_tries = 0;
1682 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1683 if (option_verbose > 2)
1684 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);
1686 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1687 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1691 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1692 if (option_verbose > 2)
1693 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1695 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1696 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1697 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1698 if (option_verbose > 2)
1699 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1701 /* End Channel Specific Login Overrides */
1702 /* Read command line options */
1704 options = strchr(opt_user, '|');
1709 context = strchr(options, '@');
1715 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1722 option = (char)options[0];
1723 if ((option >= 0) && (option <= '9'))
1729 play_announcement = 0;
1731 badoption[0] = option;
1732 badoption[1] = '\0';
1733 tmpoptions=badoption;
1734 if (option_verbose > 2)
1735 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1741 /* End command line options */
1743 if (chan->_state != AST_STATE_UP)
1744 res = ast_answer(chan);
1746 if( opt_user && !ast_strlen_zero(opt_user))
1747 ast_copy_string(user, opt_user, AST_MAX_AGENT);
1749 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1751 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1753 /* Check for password */
1754 ast_mutex_lock(&agentlock);
1757 if (!strcmp(p->agent, user) && !p->pending)
1758 ast_copy_string(xpass, p->password, sizeof(xpass));
1761 ast_mutex_unlock(&agentlock);
1763 if (!ast_strlen_zero(xpass))
1764 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1768 errmsg = "agent-incorrect";
1771 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1774 /* Check again for accuracy */
1775 ast_mutex_lock(&agentlock);
1778 ast_mutex_lock(&p->lock);
1779 if (!strcmp(p->agent, user) &&
1780 !strcmp(p->password, pass) && !p->pending) {
1781 login_state = 1; /* Successful Login */
1783 /* Ensure we can't be gotten until we're done */
1784 gettimeofday(&p->lastdisc, NULL);
1785 p->lastdisc.tv_sec++;
1787 /* Set Channel Specific Agent Overides */
1788 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1789 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1791 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1795 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1796 if (option_verbose > 2)
1797 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1799 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1800 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1801 if (p->autologoff < 0)
1803 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1804 if (option_verbose > 2)
1805 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1807 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1808 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1809 if (p->wrapuptime < 0)
1811 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1812 if (option_verbose > 2)
1813 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1815 /* End Channel Specific Agent Overides */
1817 char last_loginchan[80] = "";
1819 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1822 char tmpchan[AST_MAX_BUF] = "";
1824 /* Retrieve login chan */
1827 ast_copy_string(tmpchan, exten, sizeof(tmpchan));
1830 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1831 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1835 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1839 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);
1840 res = ast_streamfile(chan, "invalid", chan->language);
1842 res = ast_waitstream(chan, AST_DIGIT_ANY);
1855 set_agentbycallerid(p->logincallerid, NULL);
1856 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1857 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1859 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1860 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1862 p->acknowledged = 0;
1863 if (ast_strlen_zero(p->loginchan)) {
1865 filename = "agent-loggedoff";
1867 if (chan->cid.cid_num) {
1868 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1869 set_agentbycallerid(p->logincallerid, p->agent);
1871 p->logincallerid[0] = '\0';
1874 if(update_cdr && chan->cdr)
1875 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1879 p->loginchan[0] = '\0';
1880 p->logincallerid[0] = '\0';
1881 p->acknowledged = 0;
1883 ast_mutex_unlock(&p->lock);
1884 ast_mutex_unlock(&agentlock);
1885 if( !res && play_announcement==1 )
1886 res = ast_streamfile(chan, filename, chan->language);
1888 ast_waitstream(chan, "");
1889 ast_mutex_lock(&agentlock);
1890 ast_mutex_lock(&p->lock);
1892 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1894 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1897 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1899 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1901 /* Check once more just in case */
1904 if (callbackmode && !res) {
1905 /* Just say goodbye and be done with it */
1906 if (!ast_strlen_zero(p->loginchan)) {
1907 if (p->loginstart == 0)
1908 time(&p->loginstart);
1909 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1913 p->agent, p->loginchan, chan->uniqueid);
1914 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1915 if (option_verbose > 1)
1916 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1917 ast_device_state_changed("Agent/%s", p->agent);
1919 logintime = time(NULL) - p->loginstart;
1921 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1924 "Logintime: %ld\r\n"
1926 p->agent, last_loginchan, logintime, chan->uniqueid);
1927 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1928 if (option_verbose > 1)
1929 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1930 ast_device_state_changed("Agent/%s", p->agent);
1932 ast_mutex_unlock(&agentlock);
1934 res = ast_safe_sleep(chan, 500);
1935 ast_mutex_unlock(&p->lock);
1936 if (persistent_agents)
1939 #ifdef HONOR_MUSIC_CLASS
1940 /* check if the moh class was changed with setmusiconhold */
1941 if (*(chan->musicclass))
1942 ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
1944 ast_moh_start(chan, p->moh);
1945 if (p->loginstart == 0)
1946 time(&p->loginstart);
1947 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1951 p->agent, chan->name, chan->uniqueid);
1952 if (update_cdr && chan->cdr)
1953 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1954 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1955 if (option_verbose > 1)
1956 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1957 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1958 /* Login this channel and wait for it to
1964 check_availability(p, 0);
1965 ast_mutex_unlock(&p->lock);
1966 ast_mutex_unlock(&agentlock);
1967 ast_device_state_changed("Agent/%s", p->agent);
1969 ast_mutex_lock(&p->lock);
1970 if (p->chan != chan)
1972 ast_mutex_unlock(&p->lock);
1973 /* Yield here so other interested threads can kick in. */
1978 ast_mutex_lock(&agentlock);
1979 ast_mutex_lock(&p->lock);
1980 if (p->lastdisc.tv_sec) {
1981 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
1983 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1984 p->lastdisc = ast_tv(0, 0);
1988 check_availability(p, 0);
1991 ast_mutex_unlock(&p->lock);
1992 ast_mutex_unlock(&agentlock);
1993 /* Synchronize channel ownership between call to agent and itself. */
1994 ast_mutex_lock( &p->app_lock );
1995 ast_mutex_lock(&p->lock);
1996 p->owning_app = pthread_self();
1997 ast_mutex_unlock(&p->lock);
1999 res = agent_ack_sleep(p);
2001 res = ast_safe_sleep_conditional( chan, 1000,
2002 agent_cont_sleep, p );
2003 ast_mutex_unlock( &p->app_lock );
2004 if ((p->ackcall > 1) && (res == 1)) {
2005 ast_mutex_lock(&agentlock);
2006 ast_mutex_lock(&p->lock);
2007 check_availability(p, 0);
2008 ast_mutex_unlock(&p->lock);
2009 ast_mutex_unlock(&agentlock);
2014 ast_mutex_lock(&p->lock);
2015 if (res && p->owner)
2016 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
2017 /* Log us off if appropriate */
2018 if (p->chan == chan)
2020 p->acknowledged = 0;
2021 logintime = time(NULL) - p->loginstart;
2023 ast_mutex_unlock(&p->lock);
2024 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2026 "Logintime: %ld\r\n"
2028 p->agent, logintime, chan->uniqueid);
2029 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2030 if (option_verbose > 1)
2031 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
2032 /* If there is no owner, go ahead and kill it now */
2033 ast_device_state_changed("Agent/%s", p->agent);
2034 if (p->dead && !p->owner) {
2035 ast_mutex_destroy(&p->lock);
2036 ast_mutex_destroy(&p->app_lock);
2041 ast_mutex_unlock(&p->lock);
2046 ast_mutex_unlock(&p->lock);
2047 errmsg = "agent-alreadyon";
2052 ast_mutex_unlock(&p->lock);
2056 ast_mutex_unlock(&agentlock);
2058 if (!res && (max_login_tries==0 || tries < max_login_tries))
2059 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2062 LOCAL_USER_REMOVE(u);
2064 res = ast_safe_sleep(chan, 500);
2066 /* AgentLogin() exit */
2067 if (!callbackmode) {
2070 /* AgentCallbackLogin() exit*/
2073 if (login_state > 0) {
2074 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
2075 if (login_state==1) {
2076 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
2077 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
2080 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
2084 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
2086 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
2088 /* Do we need to play agent-goodbye now that we will be hanging up? */
2089 if (play_announcement==1) {
2091 res = ast_safe_sleep(chan, 1000);
2092 res = ast_streamfile(chan, agent_goodbye, chan->language);
2094 res = ast_waitstream(chan, "");
2096 res = ast_safe_sleep(chan, 1000);
2099 /* We should never get here if next priority exists when in callbackmode */
2104 * Called by the AgentLogin application (from the dial plan).
2109 * @sa callback_login_exec(), agentmonitoroutgoing_exec(), load_module().
2111 static int login_exec(struct ast_channel *chan, void *data)
2113 return __login_exec(chan, data, 0);
2117 * Called by the AgentCallbackLogin application (from the dial plan).
2122 * @sa login_exec(), agentmonitoroutgoing_exec(), load_module().
2124 static int callback_exec(struct ast_channel *chan, void *data)
2126 return __login_exec(chan, data, 1);
2130 * Sets an agent as logged in by callback in the Manager API.
2131 * It is registered on load_module() and it gets called by the manager backend.
2135 * @sa action_agents(), action_agent_logoff(), load_module().
2137 static int action_agent_callback_login(struct mansession *s, struct message *m)
2139 char *agent = astman_get_header(m, "Agent");
2140 char *exten = astman_get_header(m, "Exten");
2141 char *context = astman_get_header(m, "Context");
2142 char *wrapuptime_s = astman_get_header(m, "WrapupTime");
2143 char *ackcall_s = astman_get_header(m, "AckCall");
2144 struct agent_pvt *p;
2145 int login_state = 0;
2147 if (ast_strlen_zero(agent)) {
2148 astman_send_error(s, m, "No agent specified");
2152 if (ast_strlen_zero(exten)) {
2153 astman_send_error(s, m, "No extension specified");
2157 ast_mutex_lock(&agentlock);
2160 if (strcmp(p->agent, agent) || p->pending) {
2165 login_state = 2; /* already logged in (and on the phone)*/
2168 ast_mutex_lock(&p->lock);
2169 login_state = 1; /* Successful Login */
2170 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
2172 if (ast_strlen_zero(context))
2173 snprintf(p->loginchan, sizeof(p->loginchan), "%s", exten);
2175 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
2177 if (wrapuptime_s && !ast_strlen_zero(wrapuptime_s)) {
2178 p->wrapuptime = atoi(wrapuptime_s);
2179 if (p->wrapuptime < 0)
2183 if (ast_true(ackcall_s))
2188 if (p->loginstart == 0)
2189 time(&p->loginstart);
2190 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
2192 "Loginchan: %s\r\n",
2193 p->agent, p->loginchan);
2194 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
2195 if (option_verbose > 1)
2196 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
2197 ast_device_state_changed("Agent/%s", p->agent);
2198 ast_mutex_unlock(&p->lock);
2201 ast_mutex_unlock(&agentlock);
2203 if (login_state == 1)
2204 astman_send_ack(s, m, "Agent logged in");
2205 else if (login_state == 0)
2206 astman_send_error(s, m, "No such agent");
2207 else if (login_state == 2)
2208 astman_send_error(s, m, "Agent already logged in");
2214 * Called by the AgentMonitorOutgoing application (from the dial plan).
2219 * @sa login_exec(), callback_login_exec(), load_module().
2221 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2223 int exitifnoagentid = 0;
2225 int changeoutgoing = 0;
2227 char agent[AST_MAX_AGENT], *tmp;
2230 if (strchr(data, 'd'))
2231 exitifnoagentid = 1;
2232 if (strchr(data, 'n'))
2234 if (strchr(data, 'c'))
2237 if (chan->cid.cid_num) {
2238 char agentvar[AST_MAX_BUF];
2239 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2240 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2241 struct agent_pvt *p = agents;
2242 ast_copy_string(agent, tmp, sizeof(agent));
2243 ast_mutex_lock(&agentlock);
2245 if (!strcasecmp(p->agent, tmp)) {
2246 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2247 __agent_start_monitoring(chan, p, 1);
2252 ast_mutex_unlock(&agentlock);
2257 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);
2262 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");
2264 /* check if there is n + 101 priority */
2266 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2267 chan->priority+=100;
2268 if (option_verbose > 2)
2269 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2271 else if (exitifnoagentid)
2278 * Dump AgentCallbackLogin agents to the database for persistence
2280 static void dump_agents(void)
2282 struct agent_pvt *cur_agent = NULL;
2285 for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2286 if (cur_agent->chan)
2289 if (!ast_strlen_zero(cur_agent->loginchan)) {
2290 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2291 if (ast_db_put(pa_family, cur_agent->agent, buf))
2292 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2293 else if (option_debug)
2294 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2296 /* Delete - no agent or there is an error */
2297 ast_db_del(pa_family, cur_agent->agent);
2303 * Reload the persistent agents from astdb.
2305 static void reload_agents(void)
2308 struct ast_db_entry *db_tree;
2309 struct ast_db_entry *entry;
2310 struct agent_pvt *cur_agent;
2311 char agent_data[256];
2314 char *agent_callerid;
2316 db_tree = ast_db_gettree(pa_family, NULL);
2318 ast_mutex_lock(&agentlock);
2319 for (entry = db_tree; entry; entry = entry->next) {
2320 agent_num = entry->key + strlen(pa_family) + 2;
2323 ast_mutex_lock(&cur_agent->lock);
2324 if (strcmp(agent_num, cur_agent->agent) == 0)
2326 ast_mutex_unlock(&cur_agent->lock);
2327 cur_agent = cur_agent->next;
2330 ast_db_del(pa_family, agent_num);
2333 ast_mutex_unlock(&cur_agent->lock);
2334 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2336 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2338 agent_chan = strsep(&parse, ";");
2339 agent_callerid = strsep(&parse, ";");
2340 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2341 if (agent_callerid) {
2342 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2343 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2345 cur_agent->logincallerid[0] = '\0';
2346 if (cur_agent->loginstart == 0)
2347 time(&cur_agent->loginstart);
2348 ast_device_state_changed("Agent/%s", cur_agent->agent);
2351 ast_mutex_unlock(&agentlock);
2353 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2354 ast_db_freetree(db_tree);
2358 /*--- agent_devicestate: Part of PBX channel interface ---*/
2359 static int agent_devicestate(void *data)
2361 struct agent_pvt *p;
2363 ast_group_t groupmatch;
2366 int res = AST_DEVICE_INVALID;
2369 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2370 groupmatch = (1 << groupoff);
2371 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2372 groupmatch = (1 << groupoff);
2378 /* Check actual logged in agents first */
2379 ast_mutex_lock(&agentlock);
2382 ast_mutex_lock(&p->lock);
2383 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2385 if (res != AST_DEVICE_INUSE)
2386 res = AST_DEVICE_BUSY;
2388 if (res == AST_DEVICE_BUSY)
2389 res = AST_DEVICE_INUSE;
2390 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2391 if (res == AST_DEVICE_INVALID)
2392 res = AST_DEVICE_UNKNOWN;
2393 } else if (res == AST_DEVICE_INVALID)
2394 res = AST_DEVICE_UNAVAILABLE;
2396 if (!strcmp(data, p->agent)) {
2397 ast_mutex_unlock(&p->lock);
2401 ast_mutex_unlock(&p->lock);
2404 ast_mutex_unlock(&agentlock);
2409 * Initialize the Agents module.
2410 * This funcion is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
2412 * @returns int Always 0.
2416 /* Make sure we can register our agent channel type */
2417 if (ast_channel_register(&agent_tech)) {
2418 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2421 /* Dialplan applications */
2422 ast_register_application(app, login_exec, synopsis, descrip);
2423 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2424 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2425 /* Manager commands */
2426 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2427 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2428 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
2429 /* CLI Application */
2430 ast_cli_register(&cli_show_agents);
2431 ast_cli_register(&cli_agent_logoff);
2432 /* Read in the config */
2433 read_agent_config();
2434 if (persistent_agents)
2441 read_agent_config();
2442 if (persistent_agents)
2449 struct agent_pvt *p;
2450 /* First, take us out of the channel loop */
2451 /* Unregister CLI application */
2452 ast_cli_unregister(&cli_show_agents);
2453 ast_cli_unregister(&cli_agent_logoff);
2454 /* Unregister dialplan applications */
2455 ast_unregister_application(app);
2456 ast_unregister_application(app2);
2457 ast_unregister_application(app3);
2458 /* Unregister manager command */
2459 ast_manager_unregister("Agents");
2460 ast_manager_unregister("AgentLogoff");
2461 ast_manager_unregister("AgentCallbackLogin");
2462 /* Unregister channel */
2463 ast_channel_unregister(&agent_tech);
2464 if (!ast_mutex_lock(&agentlock)) {
2465 /* Hangup all interfaces if they have an owner */
2469 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2473 ast_mutex_unlock(&agentlock);
2475 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2488 return ASTERISK_GPL_KEY;
2493 return (char *) desc;