2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
22 * \brief Implementation of Agents (proxy channel)
24 * \author Mark Spencer <markster@digium.com>
26 * This file is the implementation of Agents modules.
27 * It is a dynamic module that is loaded by Asterisk.
29 * \arg \ref Config_agent
31 * \ingroup channel_drivers
38 #include <sys/socket.h>
42 #include <netinet/in.h>
43 #include <arpa/inet.h>
44 #include <sys/signal.h>
48 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
50 #include "asterisk/lock.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/config.h"
53 #include "asterisk/logger.h"
54 #include "asterisk/module.h"
55 #include "asterisk/pbx.h"
56 #include "asterisk/options.h"
57 #include "asterisk/lock.h"
58 #include "asterisk/sched.h"
59 #include "asterisk/io.h"
60 #include "asterisk/rtp.h"
61 #include "asterisk/acl.h"
62 #include "asterisk/callerid.h"
63 #include "asterisk/file.h"
64 #include "asterisk/cli.h"
65 #include "asterisk/app.h"
66 #include "asterisk/musiconhold.h"
67 #include "asterisk/manager.h"
68 #include "asterisk/features.h"
69 #include "asterisk/utils.h"
70 #include "asterisk/causes.h"
71 #include "asterisk/astdb.h"
72 #include "asterisk/devicestate.h"
73 #include "asterisk/monitor.h"
75 static const char desc[] = "Agent Proxy Channel";
76 static const char channeltype[] = "Agent";
77 static const char tdesc[] = "Call Agent Proxy Channel";
78 static const char config[] = "agents.conf";
80 static const char app[] = "AgentLogin";
81 static const char app2[] = "AgentCallbackLogin";
82 static const char app3[] = "AgentMonitorOutgoing";
84 static const char synopsis[] = "Call agent login";
85 static const char synopsis2[] = "Call agent callback login";
86 static const char synopsis3[] = "Record agent's outgoing call";
88 static const char descrip[] =
89 " AgentLogin([AgentNo][|options]):\n"
90 "Asks the agent to login to the system. Always returns -1. While\n"
91 "logged in, the agent can receive calls and will hear a 'beep'\n"
92 "when a new call comes in. The agent can dump the call by pressing\n"
94 "The option string may contain zero or more of the following characters:\n"
95 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
97 static const char descrip2[] =
98 " AgentCallbackLogin([AgentNo][|[options][|[exten]@context]]):\n"
99 "Asks the agent to login to the system with callback.\n"
100 "The agent's callback extension is called (optionally with the specified\n"
102 "The option string may contain zero or more of the following characters:\n"
103 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
105 static const char descrip3[] =
106 " AgentMonitorOutgoing([options]):\n"
107 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
108 "comparision of the callerid of the current interface and the global variable \n"
109 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
110 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
111 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
113 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
114 "the agentid are not specified it'll look for n+101 priority.\n"
116 " 'd' - make the app return -1 if there is an error condition and there is\n"
117 " no extension n+101\n"
118 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
119 " 'n' - don't generate the warnings when there is no callerid or the\n"
120 " agentid is not known.\n"
121 " It's handy if you want to have one context for agent and non-agent calls.\n";
123 static const char mandescr_agents[] =
124 "Description: Will list info about all possible agents.\n"
127 static const char mandescr_agent_logoff[] =
128 "Description: Sets an agent as no longer logged in.\n"
129 "Variables: (Names marked with * are required)\n"
130 " *Agent: Agent ID of the agent to log off\n"
131 " Soft: Set to 'true' to not hangup existing calls\n";
133 static const char mandescr_agent_callback_login[] =
134 "Description: Sets an agent as logged in with callback.\n"
135 "Variables: (Names marked with * are required)\n"
136 " *Agent: Agent ID of the agent to login\n"
137 " *Exten: Extension to use for callback\n"
138 " Context: Context to use for callback\n"
139 " AckCall: Set to 'true' to require an acknowledgement by '#' when agent is called back\n"
140 " WrapupTime: the minimum amount of time after disconnecting before the caller can receive a new call\n";
142 static char moh[80] = "default";
144 #define AST_MAX_AGENT 80 /**< Agent ID or Password max length */
145 #define AST_MAX_BUF 256
146 #define AST_MAX_FILENAME_LEN 256
148 /** Persistent Agents astdb family */
149 static const char pa_family[] = "/Agents";
150 /** The maximum lengh of each persistent member agent database entry */
151 #define PA_MAX_LEN 2048
152 /** queues.conf [general] option */
153 static int persistent_agents = 0;
154 static void dump_agents(void);
156 static ast_group_t group;
157 static int autologoff;
158 static int wrapuptime;
160 static int multiplelogin = 1;
162 static int maxlogintries = 3;
163 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
165 static int usecnt =0;
166 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
168 /* Protect the interface list (of pvt's) */
169 AST_MUTEX_DEFINE_STATIC(agentlock);
171 static int recordagentcalls = 0;
172 static char recordformat[AST_MAX_BUF] = "";
173 static char recordformatext[AST_MAX_BUF] = "";
174 static char urlprefix[AST_MAX_BUF] = "";
175 static char savecallsin[AST_MAX_BUF] = "";
176 static int updatecdr = 0;
177 static char beep[AST_MAX_BUF] = "beep";
179 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
182 * Structure representing an agent.
185 ast_mutex_t lock; /**< Channel private lock */
186 int dead; /**< Poised for destruction? */
187 int pending; /**< Not a real agent -- just pending a match */
188 int abouttograb; /**< About to grab */
189 int autologoff; /**< Auto timeout time */
190 int ackcall; /**< ackcall */
191 time_t loginstart; /**< When agent first logged in (0 when logged off) */
192 time_t start; /**< When call started */
193 struct timeval lastdisc; /**< When last disconnected */
194 int wrapuptime; /**< Wrapup time in ms */
195 ast_group_t group; /**< Group memberships */
196 int acknowledged; /**< Acknowledged */
197 char moh[80]; /**< Which music on hold */
198 char agent[AST_MAX_AGENT]; /**< Agent ID */
199 char password[AST_MAX_AGENT]; /**< Password for Agent login */
200 char name[AST_MAX_AGENT];
201 ast_mutex_t app_lock; /**< Synchronization between owning applications */
202 volatile pthread_t owning_app; /**< Owning application thread id */
203 volatile int app_sleep_cond; /**< Sleep condition for the login app */
204 struct ast_channel *owner; /**< Agent */
205 char loginchan[80]; /**< channel they logged in from */
206 char logincallerid[80]; /**< Caller ID they had when they logged in */
207 struct ast_channel *chan; /**< Channel we use */
208 struct agent_pvt *next; /**< Next Agent in the linked list. */
211 static struct agent_pvt *agents = NULL; /**< Holds the list of agents (loaded form agents.conf). */
213 #define CHECK_FORMATS(ast, p) do { \
215 if (ast->nativeformats != p->chan->nativeformats) { \
216 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
217 /* Native formats changed, reset things */ \
218 ast->nativeformats = p->chan->nativeformats; \
219 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
220 ast_set_read_format(ast, ast->readformat); \
221 ast_set_write_format(ast, ast->writeformat); \
223 if (p->chan->readformat != ast->rawreadformat) \
224 ast_set_read_format(p->chan, ast->rawreadformat); \
225 if (p->chan->writeformat != ast->rawwriteformat) \
226 ast_set_write_format(p->chan, ast->rawwriteformat); \
230 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
231 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
232 totally impractical combinations XXX */
234 #define CLEANUP(ast, p) do { \
237 for (x=0;x<AST_MAX_FDS;x++) {\
238 if (x != AST_MAX_FDS - 2) \
239 ast->fds[x] = p->chan->fds[x]; \
241 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
245 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
246 static int agent_devicestate(void *data);
247 static int agent_digit(struct ast_channel *ast, char digit);
248 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
249 static int agent_hangup(struct ast_channel *ast);
250 static int agent_answer(struct ast_channel *ast);
251 static struct ast_frame *agent_read(struct ast_channel *ast);
252 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
253 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
254 static int agent_sendtext(struct ast_channel *ast, const char *text);
255 static int agent_indicate(struct ast_channel *ast, int condition);
256 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
257 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
259 static const struct ast_channel_tech agent_tech = {
261 .description = tdesc,
263 .requester = agent_request,
264 .devicestate = agent_devicestate,
265 .send_digit = agent_digit,
267 .hangup = agent_hangup,
268 .answer = agent_answer,
270 .write = agent_write,
271 .send_html = agent_sendhtml,
272 .send_text = agent_sendtext,
273 .exception = agent_read,
274 .indicate = agent_indicate,
275 .fixup = agent_fixup,
276 .bridged_channel = agent_bridgedchannel,
280 * Unlink (that is, take outside of the linked list) an agent.
282 * @param agent Agent to be unlinked.
284 static void agent_unlink(struct agent_pvt *agent)
286 struct agent_pvt *p, *prev;
289 // Iterate over all agents looking for the one.
292 // Once it wal found, check if it is the first one.
294 // If it is not, tell the previous agent that the next one is the next one of the current (jumping the current).
295 prev->next = agent->next;
297 // If it is the first one, just change the general pointer to point to the second one.
298 agents = agent->next;
308 * Adds an agent to the global list of agents.
310 * @param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
311 * @param pending If it is pending or not.
312 * @return The just created agent.
313 * @sa agent_pvt, agents.
315 static struct agent_pvt *add_agent(char *agent, int pending)
320 char *password = NULL;
323 struct agent_pvt *p, *prev;
325 args = ast_strdupa(agent);
327 // Extract username (agt), password and name from agent (args).
328 if ((argc = ast_app_separate_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) {
332 while (*password && *password < 33) password++;
336 while (*name && *name < 33) name++;
339 ast_log(LOG_WARNING, "A blank agent line!\n");
342 // Are we searching for the agent here ? to see if it exists already ?
346 if (!pending && !strcmp(p->agent, agt))
353 if (!(p = ast_calloc(1, sizeof(*p))))
355 ast_copy_string(p->agent, agt, sizeof(p->agent));
356 ast_mutex_init(&p->lock);
357 ast_mutex_init(&p->app_lock);
358 p->owning_app = (pthread_t) -1;
359 p->app_sleep_cond = 1;
361 p->pending = pending;
369 ast_copy_string(p->password, password ? password : "", sizeof(p->password));
370 ast_copy_string(p->name, name ? name : "", sizeof(p->name));
371 ast_copy_string(p->moh, moh, sizeof(p->moh));
372 p->ackcall = ackcall;
373 p->autologoff = autologoff;
375 /* If someone reduces the wrapuptime and reloads, we want it
376 * to change the wrapuptime immediately on all calls */
377 if (p->wrapuptime > wrapuptime) {
378 struct timeval now = ast_tvnow();
379 /* XXX check what is this exactly */
381 /* We won't be pedantic and check the tv_usec val */
382 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
383 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
384 p->lastdisc.tv_usec = now.tv_usec;
387 p->wrapuptime = wrapuptime;
397 * Deletes an agent after doing some clean up.
398 * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
399 * @param p Agent to be deleted.
402 static int agent_cleanup(struct agent_pvt *p)
404 struct ast_channel *chan = p->owner;
406 chan->tech_pvt = NULL;
407 p->app_sleep_cond = 1;
408 /* Release ownership of the agent to other threads (presumably running the login app). */
409 ast_mutex_unlock(&p->app_lock);
411 ast_channel_free(chan);
413 ast_mutex_destroy(&p->lock);
414 ast_mutex_destroy(&p->app_lock);
420 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
422 static int agent_answer(struct ast_channel *ast)
424 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
428 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
430 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
431 char filename[AST_MAX_BUF];
436 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
437 /* substitute . for - */
438 if ((pointer = strchr(filename, '.')))
440 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
441 ast_monitor_start(ast, recordformat, tmp, needlock);
442 ast_monitor_setjoinfiles(ast, 1);
443 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
445 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
448 ast->cdr = ast_cdr_alloc();
449 ast_cdr_setuserfield(ast, tmp2);
452 ast_log(LOG_ERROR, "Recording already started on that call.\n");
456 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
458 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
461 static struct ast_frame *agent_read(struct ast_channel *ast)
463 struct agent_pvt *p = ast->tech_pvt;
464 struct ast_frame *f = NULL;
465 static struct ast_frame null_frame = { AST_FRAME_NULL, };
466 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
467 ast_mutex_lock(&p->lock);
468 CHECK_FORMATS(ast, p);
470 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
471 if (ast->fdno == AST_MAX_FDS - 3)
472 p->chan->fdno = AST_MAX_FDS - 2;
474 p->chan->fdno = ast->fdno;
475 f = ast_read(p->chan);
479 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
481 p->chan->_bridge = NULL;
482 /* Note that we don't hangup if it's not a callback because Asterisk will do it
483 for us when the PBX instance that called login finishes */
484 if (!ast_strlen_zero(p->loginchan)) {
486 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
488 if (p->wrapuptime && p->acknowledged)
489 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
495 /* if acknowledgement is not required, and the channel is up, we may have missed
496 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
497 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
499 switch (f->frametype) {
500 case AST_FRAME_CONTROL:
501 if (f->subclass == AST_CONTROL_ANSWER) {
503 if (option_verbose > 2)
504 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
505 /* Don't pass answer along */
510 /* Use the builtin answer frame for the
511 recording start check below. */
518 if (!p->acknowledged && (f->subclass == '#')) {
519 if (option_verbose > 2)
520 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
524 } else if (f->subclass == '*') {
525 /* terminates call */
530 case AST_FRAME_VOICE:
531 /* don't pass voice until the call is acknowledged */
532 if (!p->acknowledged) {
541 if (p->chan && !p->chan->_bridge) {
542 if (strcasecmp(p->chan->type, "Local")) {
543 p->chan->_bridge = ast;
545 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
548 ast_mutex_unlock(&p->lock);
549 if (recordagentcalls && f == &answer_frame)
550 agent_start_monitoring(ast,0);
554 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
556 struct agent_pvt *p = ast->tech_pvt;
558 ast_mutex_lock(&p->lock);
560 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
561 ast_mutex_unlock(&p->lock);
565 static int agent_sendtext(struct ast_channel *ast, const char *text)
567 struct agent_pvt *p = ast->tech_pvt;
569 ast_mutex_lock(&p->lock);
571 res = ast_sendtext(p->chan, text);
572 ast_mutex_unlock(&p->lock);
576 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
578 struct agent_pvt *p = ast->tech_pvt;
580 CHECK_FORMATS(ast, p);
581 ast_mutex_lock(&p->lock);
583 if ((f->frametype != AST_FRAME_VOICE) ||
584 (f->subclass == p->chan->writeformat)) {
585 res = ast_write(p->chan, f);
587 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
593 ast_mutex_unlock(&p->lock);
597 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
599 struct agent_pvt *p = newchan->tech_pvt;
600 ast_mutex_lock(&p->lock);
601 if (p->owner != oldchan) {
602 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
603 ast_mutex_unlock(&p->lock);
607 ast_mutex_unlock(&p->lock);
611 static int agent_indicate(struct ast_channel *ast, int condition)
613 struct agent_pvt *p = ast->tech_pvt;
615 ast_mutex_lock(&p->lock);
617 res = ast_indicate(p->chan, condition);
620 ast_mutex_unlock(&p->lock);
624 static int agent_digit(struct ast_channel *ast, char digit)
626 struct agent_pvt *p = ast->tech_pvt;
628 ast_mutex_lock(&p->lock);
630 res = p->chan->tech->send_digit(p->chan, digit);
633 ast_mutex_unlock(&p->lock);
637 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
639 struct agent_pvt *p = ast->tech_pvt;
642 ast_mutex_lock(&p->lock);
646 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
647 newstate = AST_STATE_DIALING;
650 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
653 ast_mutex_unlock(&p->lock);
655 ast_setstate(ast, newstate);
657 } else if (!ast_strlen_zero(p->loginchan)) {
659 /* Call on this agent */
660 if (option_verbose > 2)
661 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
662 if (p->chan->cid.cid_num)
663 free(p->chan->cid.cid_num);
664 p->chan->cid.cid_num = ast_strdup(ast->cid.cid_num);
665 if (p->chan->cid.cid_name)
666 free(p->chan->cid.cid_name);
667 p->chan->cid.cid_name = ast_strdup(ast->cid.cid_name);
668 ast_channel_inherit_variables(ast, p->chan);
669 res = ast_call(p->chan, p->loginchan, 0);
671 ast_mutex_unlock(&p->lock);
674 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
675 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
676 res = ast_streamfile(p->chan, beep, p->chan->language);
677 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
679 res = ast_waitstream(p->chan, "");
680 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
683 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
684 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
686 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
693 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
694 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
696 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
700 /* Call is immediately up, or might need ack */
702 newstate = AST_STATE_RINGING;
704 newstate = AST_STATE_UP;
705 if (recordagentcalls)
706 agent_start_monitoring(ast,0);
712 ast_mutex_unlock(&p->lock);
714 ast_setstate(ast, newstate);
718 /* store/clear the global variable that stores agentid based on the callerid */
719 static void set_agentbycallerid(const char *callerid, const char *agent)
721 char buf[AST_MAX_BUF];
723 /* if there is no Caller ID, nothing to do */
724 if (ast_strlen_zero(callerid))
727 snprintf(buf, sizeof(buf), "%s_%s",GETAGENTBYCALLERID, callerid);
728 pbx_builtin_setvar_helper(NULL, buf, agent);
731 static int agent_hangup(struct ast_channel *ast)
733 struct agent_pvt *p = ast->tech_pvt;
735 ast_mutex_lock(&p->lock);
737 ast->tech_pvt = NULL;
738 p->app_sleep_cond = 1;
741 /* if they really are hung up then set start to 0 so the test
742 * later if we're called on an already downed channel
743 * doesn't cause an agent to be logged out like when
744 * agent_request() is followed immediately by agent_hangup()
745 * as in apps/app_chanisavail.c:chanavail_exec()
748 ast_mutex_lock(&usecnt_lock);
750 ast_mutex_unlock(&usecnt_lock);
752 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
753 if (p->start && (ast->_state != AST_STATE_UP)) {
754 howlong = time(NULL) - p->start;
756 } else if (ast->_state == AST_STATE_RESERVED) {
761 p->chan->_bridge = NULL;
762 /* If they're dead, go ahead and hang up on the agent now */
763 if (!ast_strlen_zero(p->loginchan)) {
764 /* Store last disconnect time */
766 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
768 p->lastdisc = ast_tv(0,0);
770 /* Recognize the hangup and pass it along immediately */
774 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
775 if (howlong && p->autologoff && (howlong > p->autologoff)) {
776 char agent[AST_MAX_AGENT] = "";
777 long logintime = time(NULL) - p->loginstart;
779 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
780 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
784 "Reason: Autologoff\r\n"
786 p->agent, p->loginchan, logintime, ast->uniqueid);
787 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
788 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
789 set_agentbycallerid(p->logincallerid, NULL);
790 ast_device_state_changed("Agent/%s", p->agent);
791 p->loginchan[0] = '\0';
792 p->logincallerid[0] = '\0';
793 if (persistent_agents)
796 } else if (p->dead) {
797 ast_mutex_lock(&p->chan->lock);
798 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
799 ast_mutex_unlock(&p->chan->lock);
801 ast_mutex_lock(&p->chan->lock);
802 ast_moh_start(p->chan, p->moh);
803 ast_mutex_unlock(&p->chan->lock);
806 ast_mutex_unlock(&p->lock);
807 ast_device_state_changed("Agent/%s", p->agent);
810 ast_mutex_lock(&agentlock);
812 ast_mutex_unlock(&agentlock);
814 if (p->abouttograb) {
815 /* Let the "about to grab" thread know this isn't valid anymore, and let it
818 } else if (p->dead) {
819 ast_mutex_destroy(&p->lock);
820 ast_mutex_destroy(&p->app_lock);
824 /* Not dead -- check availability now */
825 ast_mutex_lock(&p->lock);
826 /* Store last disconnect time */
827 p->lastdisc = ast_tvnow();
828 ast_mutex_unlock(&p->lock);
830 /* Release ownership of the agent to other threads (presumably running the login app). */
831 ast_mutex_unlock(&p->app_lock);
836 static int agent_cont_sleep( void *data )
841 p = (struct agent_pvt *)data;
843 ast_mutex_lock(&p->lock);
844 res = p->app_sleep_cond;
845 if (p->lastdisc.tv_sec) {
846 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime)
849 ast_mutex_unlock(&p->lock);
852 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
857 static int agent_ack_sleep( void *data )
864 /* Wait a second and look for something */
866 p = (struct agent_pvt *)data;
869 to = ast_waitfor(p->chan, to);
878 f = ast_read(p->chan);
883 if (f->frametype == AST_FRAME_DTMF)
888 ast_mutex_lock(&p->lock);
889 if (!p->app_sleep_cond) {
890 ast_mutex_unlock(&p->lock);
893 } else if (res == '#') {
894 ast_mutex_unlock(&p->lock);
898 ast_mutex_unlock(&p->lock);
906 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
908 struct agent_pvt *p = bridge->tech_pvt;
909 struct ast_channel *ret=NULL;
913 ret = bridge->_bridge;
914 else if (chan == bridge->_bridge)
919 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
923 /*--- agent_new: Create new agent channel ---*/
924 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
926 struct ast_channel *tmp;
927 struct ast_frame null_frame = { AST_FRAME_NULL };
930 ast_log(LOG_WARNING, "No channel? :(\n");
934 tmp = ast_channel_alloc(0);
936 tmp->tech = &agent_tech;
938 tmp->nativeformats = p->chan->nativeformats;
939 tmp->writeformat = p->chan->writeformat;
940 tmp->rawwriteformat = p->chan->writeformat;
941 tmp->readformat = p->chan->readformat;
942 tmp->rawreadformat = p->chan->readformat;
943 ast_copy_string(tmp->language, p->chan->language, sizeof(tmp->language));
944 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
945 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
947 tmp->nativeformats = AST_FORMAT_SLINEAR;
948 tmp->writeformat = AST_FORMAT_SLINEAR;
949 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
950 tmp->readformat = AST_FORMAT_SLINEAR;
951 tmp->rawreadformat = AST_FORMAT_SLINEAR;
954 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
956 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
957 tmp->type = channeltype;
958 /* Safe, agentlock already held */
959 ast_setstate(tmp, state);
962 ast_mutex_lock(&usecnt_lock);
964 ast_mutex_unlock(&usecnt_lock);
965 ast_update_use_count();
967 /* Wake up and wait for other applications (by definition the login app)
968 * to release this channel). Takes ownership of the agent channel
969 * to this thread only.
970 * For signalling the other thread, ast_queue_frame is used until we
971 * can safely use signals for this purpose. The pselect() needs to be
972 * implemented in the kernel for this.
974 p->app_sleep_cond = 0;
975 if( ast_mutex_trylock(&p->app_lock) )
978 ast_queue_frame(p->chan, &null_frame);
979 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
980 ast_mutex_lock(&p->app_lock);
981 ast_mutex_lock(&p->lock);
985 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
987 tmp->tech_pvt = NULL;
988 p->app_sleep_cond = 1;
989 ast_channel_free( tmp );
990 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
991 ast_mutex_unlock(&p->app_lock);
995 p->owning_app = pthread_self();
996 /* After the above step, there should not be any blockers. */
998 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
999 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
1002 ast_moh_stop(p->chan);
1005 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
1011 * Read configuration data. The file named agents.conf.
1013 * @returns Always 0, or so it seems.
1015 static int read_agent_config(void)
1017 struct ast_config *cfg;
1018 struct ast_variable *v;
1019 struct agent_pvt *p, *pl, *pn;
1026 cfg = ast_config_load(config);
1028 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1031 ast_mutex_lock(&agentlock);
1037 strcpy(moh, "default");
1038 /* set the default recording values */
1039 recordagentcalls = 0;
1040 strcpy(recordformat, "wav");
1041 strcpy(recordformatext, "wav");
1042 urlprefix[0] = '\0';
1043 savecallsin[0] = '\0';
1045 /* Read in [general] section for persistance */
1046 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1047 persistent_agents = ast_true(general_val);
1048 if (ast_false(ast_variable_retrieve(cfg, "general", "multiplelogin") ) )
1051 /* Read in the [agents] section */
1052 v = ast_variable_browse(cfg, "agents");
1054 /* Create the interface list */
1055 if (!strcasecmp(v->name, "agent")) {
1056 add_agent(v->value, 0);
1057 } else if (!strcasecmp(v->name, "group")) {
1058 group = ast_get_group(v->value);
1059 } else if (!strcasecmp(v->name, "autologoff")) {
1060 autologoff = atoi(v->value);
1063 } else if (!strcasecmp(v->name, "ackcall")) {
1064 if (!strcasecmp(v->value, "always"))
1066 else if (ast_true(v->value))
1070 } else if (!strcasecmp(v->name, "wrapuptime")) {
1071 wrapuptime = atoi(v->value);
1074 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1075 maxlogintries = atoi(v->value);
1076 if (maxlogintries < 0)
1078 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1079 strcpy(agentgoodbye,v->value);
1080 } else if (!strcasecmp(v->name, "musiconhold")) {
1081 ast_copy_string(moh, v->value, sizeof(moh));
1082 } else if (!strcasecmp(v->name, "updatecdr")) {
1083 if (ast_true(v->value))
1087 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1088 recordagentcalls = ast_true(v->value);
1089 } else if (!strcasecmp(v->name, "recordformat")) {
1090 ast_copy_string(recordformat, v->value, sizeof(recordformat));
1091 if (!strcasecmp(v->value, "wav49"))
1092 strcpy(recordformatext, "WAV");
1094 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1095 } else if (!strcasecmp(v->name, "urlprefix")) {
1096 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1097 if (urlprefix[strlen(urlprefix) - 1] != '/')
1098 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1099 } else if (!strcasecmp(v->name, "savecallsin")) {
1100 if (v->value[0] == '/')
1101 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1103 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1104 if (savecallsin[strlen(savecallsin) - 1] != '/')
1105 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1106 } else if (!strcasecmp(v->name, "custom_beep")) {
1107 ast_copy_string(beep, v->value, sizeof(beep));
1121 /* Destroy if appropriate */
1124 ast_mutex_destroy(&p->lock);
1125 ast_mutex_destroy(&p->app_lock);
1128 /* Cause them to hang up */
1129 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1136 ast_mutex_unlock(&agentlock);
1137 ast_config_destroy(cfg);
1141 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1143 struct ast_channel *chan=NULL, *parent=NULL;
1144 struct agent_pvt *p;
1148 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1150 ast_mutex_lock(&agentlock);
1153 if (p == newlyavailable) {
1157 ast_mutex_lock(&p->lock);
1158 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1160 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1161 /* We found a pending call, time to merge */
1162 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1165 ast_mutex_unlock(&p->lock);
1168 ast_mutex_unlock(&p->lock);
1172 ast_mutex_unlock(&agentlock);
1173 if (parent && chan) {
1174 if (newlyavailable->ackcall > 1) {
1175 /* Don't do beep here */
1178 if (option_debug > 2)
1179 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1180 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1181 if (option_debug > 2)
1182 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1184 res = ast_waitstream(newlyavailable->chan, "");
1185 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1189 /* Note -- parent may have disappeared */
1190 if (p->abouttograb) {
1191 newlyavailable->acknowledged = 1;
1192 /* Safe -- agent lock already held */
1193 ast_setstate(parent, AST_STATE_UP);
1194 ast_setstate(chan, AST_STATE_UP);
1195 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1196 /* Go ahead and mark the channel as a zombie so that masquerade will
1197 destroy it for us, and we need not call ast_hangup */
1198 ast_mutex_lock(&parent->lock);
1199 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1200 ast_channel_masquerade(parent, chan);
1201 ast_mutex_unlock(&parent->lock);
1205 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1206 agent_cleanup(newlyavailable);
1210 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1211 agent_cleanup(newlyavailable);
1217 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1219 struct agent_pvt *p;
1222 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1224 ast_mutex_lock(&agentlock);
1227 if (p == newlyavailable) {
1231 ast_mutex_lock(&p->lock);
1232 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1234 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1235 ast_mutex_unlock(&p->lock);
1238 ast_mutex_unlock(&p->lock);
1242 ast_mutex_unlock(&agentlock);
1244 ast_mutex_unlock(&newlyavailable->lock);
1245 if (option_debug > 2)
1246 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1247 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1248 if (option_debug > 2)
1249 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1251 res = ast_waitstream(newlyavailable->chan, "");
1253 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1255 ast_mutex_lock(&newlyavailable->lock);
1260 /* return 1 if multiple login is fine, 0 if it is not and we find a match, -1 if multiplelogin is not allowed and we dont find a match. */
1261 static int allow_multiple_login(char *chan,char *context)
1263 struct agent_pvt *p;
1272 snprintf(loginchan, sizeof(loginchan), "%s@%s", chan, !ast_strlen_zero(context) ? context : "default");
1276 if(!strcasecmp(chan, p->loginchan))
1283 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1284 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1286 struct agent_pvt *p;
1287 struct ast_channel *chan = NULL;
1289 ast_group_t groupmatch;
1296 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1297 groupmatch = (1 << groupoff);
1298 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1299 groupmatch = (1 << groupoff);
1305 /* Check actual logged in agents first */
1306 ast_mutex_lock(&agentlock);
1309 ast_mutex_lock(&p->lock);
1310 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1311 ast_strlen_zero(p->loginchan)) {
1314 if (!p->lastdisc.tv_sec) {
1315 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1316 if (!p->owner && p->chan) {
1318 chan = agent_new(p, AST_STATE_DOWN);
1321 ast_mutex_unlock(&p->lock);
1326 ast_mutex_unlock(&p->lock);
1332 ast_mutex_lock(&p->lock);
1333 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1334 if (p->chan || !ast_strlen_zero(p->loginchan))
1338 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1340 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1341 p->lastdisc = ast_tv(0, 0);
1342 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1343 if (!p->owner && p->chan) {
1344 /* Could still get a fixed agent */
1345 chan = agent_new(p, AST_STATE_DOWN);
1346 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1347 /* Adjustable agent */
1348 p->chan = ast_request("Local", format, p->loginchan, cause);
1350 chan = agent_new(p, AST_STATE_DOWN);
1353 ast_mutex_unlock(&p->lock);
1358 ast_mutex_unlock(&p->lock);
1363 if (!chan && waitforagent) {
1364 /* No agent available -- but we're requesting to wait for one.
1365 Allocate a place holder */
1368 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1369 p = add_agent(data, 1);
1370 p->group = groupmatch;
1371 chan = agent_new(p, AST_STATE_DOWN);
1373 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1376 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1379 *cause = AST_CAUSE_BUSY;
1381 *cause = AST_CAUSE_UNREGISTERED;
1382 ast_mutex_unlock(&agentlock);
1386 static int powerof(unsigned int v)
1389 for (x=0;x<32;x++) {
1390 if (v & (1 << x)) return x;
1396 * Lists agents and their status to the Manager API.
1397 * It is registered on load_module() and it gets called by the manager backend.
1401 * @sa action_agent_logoff(), action_agent_callback_login(), load_module().
1403 static int action_agents(struct mansession *s, struct message *m)
1405 char *id = astman_get_header(m,"ActionID");
1406 char idText[256] = "";
1408 struct agent_pvt *p;
1409 char *username = NULL;
1410 char *loginChan = NULL;
1411 char *talkingtoChan = NULL;
1412 char *status = NULL;
1414 if (!ast_strlen_zero(id))
1415 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1416 astman_send_ack(s, m, "Agents will follow");
1417 ast_mutex_lock(&agentlock);
1420 ast_mutex_lock(&p->lock);
1423 AGENT_LOGGEDOFF - Agent isn't logged in
1424 AGENT_IDLE - Agent is logged in, and waiting for call
1425 AGENT_ONCALL - Agent is logged in, and on a call
1426 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1428 if(!ast_strlen_zero(p->name)) {
1434 /* Set a default status. It 'should' get changed. */
1435 status = "AGENT_UNKNOWN";
1437 if (!ast_strlen_zero(p->loginchan) && !p->chan) {
1438 loginChan = p->loginchan;
1439 talkingtoChan = "n/a";
1440 status = "AGENT_IDLE";
1441 if (p->acknowledged) {
1442 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
1443 loginChan = chanbuf;
1445 } else if (p->chan) {
1446 loginChan = ast_strdupa(p->chan->name);
1447 if (p->owner && p->owner->_bridge) {
1448 talkingtoChan = p->chan->cid.cid_num;
1449 status = "AGENT_ONCALL";
1451 talkingtoChan = "n/a";
1452 status = "AGENT_IDLE";
1456 talkingtoChan = "n/a";
1457 status = "AGENT_LOGGEDOFF";
1460 ast_cli(s->fd, "Event: Agents\r\n"
1464 "LoggedInChan: %s\r\n"
1465 "LoggedInTime: %d\r\n"
1469 p->agent, username, status, loginChan, (int)p->loginstart, talkingtoChan, idText);
1470 ast_mutex_unlock(&p->lock);
1473 ast_mutex_unlock(&agentlock);
1474 ast_cli(s->fd, "Event: AgentsComplete\r\n"
1480 static int agent_logoff(char *agent, int soft)
1482 struct agent_pvt *p;
1484 int ret = -1; /* Return -1 if no agent if found */
1486 for (p=agents; p; p=p->next) {
1487 if (!strcasecmp(p->agent, agent)) {
1490 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1493 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1496 ret = 0; /* found an agent => return 0 */
1497 logintime = time(NULL) - p->loginstart;
1500 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1503 "Logintime: %ld\r\n",
1504 p->agent, p->loginchan, logintime);
1505 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1506 set_agentbycallerid(p->logincallerid, NULL);
1507 p->loginchan[0] = '\0';
1508 p->logincallerid[0] = '\0';
1509 ast_device_state_changed("Agent/%s", p->agent);
1510 if (persistent_agents)
1519 static int agent_logoff_cmd(int fd, int argc, char **argv)
1524 if (argc < 3 || argc > 4)
1525 return RESULT_SHOWUSAGE;
1526 if (argc == 4 && strcasecmp(argv[3], "soft"))
1527 return RESULT_SHOWUSAGE;
1529 agent = argv[2] + 6;
1530 ret = agent_logoff(agent, argc == 4);
1532 ast_cli(fd, "Logging out %s\n", agent);
1534 return RESULT_SUCCESS;
1538 * Sets an agent as no longer logged in in the Manager API.
1539 * It is registered on load_module() and it gets called by the manager backend.
1543 * @sa action_agents(), action_agent_callback_login(), load_module().
1545 static int action_agent_logoff(struct mansession *s, struct message *m)
1547 char *agent = astman_get_header(m, "Agent");
1548 char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1550 int ret; /* return value of agent_logoff */
1552 if (ast_strlen_zero(agent)) {
1553 astman_send_error(s, m, "No agent specified");
1557 if (ast_true(soft_s))
1562 ret = agent_logoff(agent, soft);
1564 astman_send_ack(s, m, "Agent logged out");
1566 astman_send_error(s, m, "No such agent");
1571 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1573 struct agent_pvt *p;
1574 char name[AST_MAX_AGENT];
1578 for (p=agents; p; p=p->next) {
1579 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1580 if (!strncasecmp(word, name, strlen(word))) {
1581 if (++which > state) {
1582 return ast_strdup(name);
1586 } else if (pos == 3 && state == 0) {
1587 return ast_strdup("soft");
1593 * Show agents in cli.
1595 static int agents_show(int fd, int argc, char **argv)
1597 struct agent_pvt *p;
1598 char username[AST_MAX_BUF];
1599 char location[AST_MAX_BUF] = "";
1600 char talkingto[AST_MAX_BUF] = "";
1601 char moh[AST_MAX_BUF];
1602 int count_agents = 0; /* Number of agents configured */
1603 int online_agents = 0; /* Number of online agents */
1604 int offline_agents = 0; /* Number of offline agents */
1606 return RESULT_SHOWUSAGE;
1607 ast_mutex_lock(&agentlock);
1610 ast_mutex_lock(&p->lock);
1613 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1615 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1617 if (!ast_strlen_zero(p->name))
1618 snprintf(username, sizeof(username), "(%s) ", p->name);
1622 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1623 if (p->owner && ast_bridged_channel(p->owner)) {
1624 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1626 strcpy(talkingto, " is idle");
1629 } else if (!ast_strlen_zero(p->loginchan)) {
1630 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1631 talkingto[0] = '\0';
1633 if (p->acknowledged)
1634 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1636 strcpy(location, "not logged in");
1637 talkingto[0] = '\0';
1640 if (!ast_strlen_zero(p->moh))
1641 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1642 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1643 username, location, talkingto, moh);
1646 ast_mutex_unlock(&p->lock);
1649 ast_mutex_unlock(&agentlock);
1650 if ( !count_agents ) {
1651 ast_cli(fd, "No Agents are configured in %s\n",config);
1653 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1657 return RESULT_SUCCESS;
1660 static char show_agents_usage[] =
1661 "Usage: show agents\n"
1662 " Provides summary information on agents.\n";
1664 static char agent_logoff_usage[] =
1665 "Usage: agent logoff <channel> [soft]\n"
1666 " Sets an agent as no longer logged in.\n"
1667 " If 'soft' is specified, do not hangup existing calls.\n";
1669 static struct ast_cli_entry cli_show_agents = {
1670 { "show", "agents", NULL }, agents_show,
1671 "Show status of agents", show_agents_usage, NULL };
1673 static struct ast_cli_entry cli_agent_logoff = {
1674 { "agent", "logoff", NULL }, agent_logoff_cmd,
1675 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1677 STANDARD_LOCAL_USER;
1681 * \brief Log in agent application.
1685 * \param callbackmode non-zero for AgentCallbackLogin
1687 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1691 int max_login_tries = maxlogintries;
1692 struct agent_pvt *p;
1693 struct localuser *u;
1694 int login_state = 0;
1695 char user[AST_MAX_AGENT] = "";
1696 char pass[AST_MAX_AGENT];
1697 char agent[AST_MAX_AGENT] = "";
1698 char xpass[AST_MAX_AGENT] = "";
1701 AST_DECLARE_APP_ARGS(args,
1702 AST_APP_ARG(agent_id);
1703 AST_APP_ARG(options);
1704 AST_APP_ARG(extension);
1706 const char *tmpoptions = NULL;
1707 char *context = NULL;
1708 int play_announcement = 1;
1709 char agent_goodbye[AST_MAX_FILENAME_LEN];
1710 int update_cdr = updatecdr;
1711 char *filename = "agent-loginok";
1712 char tmpchan[AST_MAX_BUF] = "";
1716 if (!(parse = ast_strdupa(data))) {
1717 ast_log(LOG_ERROR, "Out of memory!\n");
1718 LOCAL_USER_REMOVE(u);
1722 AST_STANDARD_APP_ARGS(args, parse);
1724 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1726 /* Set Channel Specific Login Overrides */
1727 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1728 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1729 if (max_login_tries < 0)
1730 max_login_tries = 0;
1731 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1732 if (option_verbose > 2)
1733 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);
1735 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1736 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1740 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1741 if (option_verbose > 2)
1742 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1744 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1745 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1746 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1747 if (option_verbose > 2)
1748 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1750 /* End Channel Specific Login Overrides */
1752 if (callbackmode && args.extension) {
1753 parse = args.extension;
1754 args.extension = strsep(&parse, "@");
1758 if (!ast_strlen_zero(args.options)) {
1759 if (strchr(args.options, 's')) {
1760 play_announcement = 0;
1764 if (chan->_state != AST_STATE_UP)
1765 res = ast_answer(chan);
1767 if (!ast_strlen_zero(args.agent_id))
1768 ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1770 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1772 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1774 /* Check for password */
1775 ast_mutex_lock(&agentlock);
1778 if (!strcmp(p->agent, user) && !p->pending)
1779 ast_copy_string(xpass, p->password, sizeof(xpass));
1782 ast_mutex_unlock(&agentlock);
1784 if (!ast_strlen_zero(xpass))
1785 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1789 errmsg = "agent-incorrect";
1792 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1795 /* Check again for accuracy */
1796 ast_mutex_lock(&agentlock);
1799 ast_mutex_lock(&p->lock);
1800 if (!strcmp(p->agent, user) &&
1801 !strcmp(p->password, pass) && !p->pending) {
1802 login_state = 1; /* Successful Login */
1804 /* Ensure we can't be gotten until we're done */
1805 gettimeofday(&p->lastdisc, NULL);
1806 p->lastdisc.tv_sec++;
1808 /* Set Channel Specific Agent Overides */
1809 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1810 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1812 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1816 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1817 if (option_verbose > 2)
1818 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1820 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1821 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1822 if (p->autologoff < 0)
1824 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1825 if (option_verbose > 2)
1826 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1828 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1829 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1830 if (p->wrapuptime < 0)
1832 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1833 if (option_verbose > 2)
1834 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1836 /* End Channel Specific Agent Overides */
1838 char last_loginchan[80] = "";
1840 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1844 /* Retrieve login chan */
1846 if (!ast_strlen_zero(args.extension)) {
1847 ast_copy_string(tmpchan, args.extension, sizeof(tmpchan));
1850 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1851 if (ast_strlen_zero(tmpchan) )
1853 if(ast_exists_extension(chan, !ast_strlen_zero(context) ? context : "default", tmpchan,1, NULL) ) {
1854 if(!allow_multiple_login(tmpchan,context) ) {
1855 args.extension = NULL;
1860 if (args.extension) {
1861 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", args.extension, p->agent);
1862 args.extension = NULL;
1865 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, !ast_strlen_zero(context) ? context : "default", p->agent);
1866 res = ast_streamfile(chan, "invalid", chan->language);
1868 res = ast_waitstream(chan, AST_DIGIT_ANY);
1879 args.extension = tmpchan;
1881 set_agentbycallerid(p->logincallerid, NULL);
1882 if (!ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1883 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1885 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1886 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1888 p->acknowledged = 0;
1889 if (ast_strlen_zero(p->loginchan)) {
1891 filename = "agent-loggedoff";
1893 if (chan->cid.cid_num) {
1894 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1895 set_agentbycallerid(p->logincallerid, p->agent);
1897 p->logincallerid[0] = '\0';
1900 if(update_cdr && chan->cdr)
1901 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1905 p->loginchan[0] = '\0';
1906 p->logincallerid[0] = '\0';
1907 p->acknowledged = 0;
1909 ast_mutex_unlock(&p->lock);
1910 ast_mutex_unlock(&agentlock);
1911 if( !res && play_announcement==1 )
1912 res = ast_streamfile(chan, filename, chan->language);
1914 ast_waitstream(chan, "");
1915 ast_mutex_lock(&agentlock);
1916 ast_mutex_lock(&p->lock);
1918 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1920 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1923 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1925 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1927 /* Check once more just in case */
1930 if (callbackmode && !res) {
1931 /* Just say goodbye and be done with it */
1932 if (!ast_strlen_zero(p->loginchan)) {
1933 if (p->loginstart == 0)
1934 time(&p->loginstart);
1935 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1939 p->agent, p->loginchan, chan->uniqueid);
1940 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1941 if (option_verbose > 1)
1942 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1943 ast_device_state_changed("Agent/%s", p->agent);
1945 logintime = time(NULL) - p->loginstart;
1947 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1950 "Logintime: %ld\r\n"
1952 p->agent, last_loginchan, logintime, chan->uniqueid);
1953 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1954 if (option_verbose > 1)
1955 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1956 ast_device_state_changed("Agent/%s", p->agent);
1958 ast_mutex_unlock(&agentlock);
1960 res = ast_safe_sleep(chan, 500);
1961 ast_mutex_unlock(&p->lock);
1962 if (persistent_agents)
1965 #ifdef HONOR_MUSIC_CLASS
1966 /* check if the moh class was changed with setmusiconhold */
1967 if (*(chan->musicclass))
1968 ast_copy_string(p->moh, chan->musicclass, sizeof(p->moh));
1970 ast_moh_start(chan, p->moh);
1971 if (p->loginstart == 0)
1972 time(&p->loginstart);
1973 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1977 p->agent, chan->name, chan->uniqueid);
1978 if (update_cdr && chan->cdr)
1979 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1980 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1981 if (option_verbose > 1)
1982 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1983 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1984 /* Login this channel and wait for it to
1990 check_availability(p, 0);
1991 ast_mutex_unlock(&p->lock);
1992 ast_mutex_unlock(&agentlock);
1993 ast_device_state_changed("Agent/%s", p->agent);
1995 ast_mutex_lock(&p->lock);
1996 if (p->chan != chan)
1998 ast_mutex_unlock(&p->lock);
1999 /* Yield here so other interested threads can kick in. */
2004 ast_mutex_lock(&agentlock);
2005 ast_mutex_lock(&p->lock);
2006 if (p->lastdisc.tv_sec) {
2007 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > p->wrapuptime) {
2009 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
2010 p->lastdisc = ast_tv(0, 0);
2014 check_availability(p, 0);
2017 ast_mutex_unlock(&p->lock);
2018 ast_mutex_unlock(&agentlock);
2019 /* Synchronize channel ownership between call to agent and itself. */
2020 ast_mutex_lock( &p->app_lock );
2021 ast_mutex_lock(&p->lock);
2022 p->owning_app = pthread_self();
2023 ast_mutex_unlock(&p->lock);
2025 res = agent_ack_sleep(p);
2027 res = ast_safe_sleep_conditional( chan, 1000,
2028 agent_cont_sleep, p );
2029 ast_mutex_unlock( &p->app_lock );
2030 if ((p->ackcall > 1) && (res == 1)) {
2031 ast_mutex_lock(&agentlock);
2032 ast_mutex_lock(&p->lock);
2033 check_availability(p, 0);
2034 ast_mutex_unlock(&p->lock);
2035 ast_mutex_unlock(&agentlock);
2040 ast_mutex_lock(&p->lock);
2041 if (res && p->owner)
2042 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
2043 /* Log us off if appropriate */
2044 if (p->chan == chan)
2046 p->acknowledged = 0;
2047 logintime = time(NULL) - p->loginstart;
2049 ast_mutex_unlock(&p->lock);
2050 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2052 "Logintime: %ld\r\n"
2054 p->agent, logintime, chan->uniqueid);
2055 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2056 if (option_verbose > 1)
2057 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
2058 /* If there is no owner, go ahead and kill it now */
2059 ast_device_state_changed("Agent/%s", p->agent);
2060 if (p->dead && !p->owner) {
2061 ast_mutex_destroy(&p->lock);
2062 ast_mutex_destroy(&p->app_lock);
2067 ast_mutex_unlock(&p->lock);
2072 ast_mutex_unlock(&p->lock);
2073 errmsg = "agent-alreadyon";
2078 ast_mutex_unlock(&p->lock);
2082 ast_mutex_unlock(&agentlock);
2084 if (!res && (max_login_tries==0 || tries < max_login_tries))
2085 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2089 res = ast_safe_sleep(chan, 500);
2091 /* AgentLogin() exit */
2092 if (!callbackmode) {
2093 LOCAL_USER_REMOVE(u);
2096 /* AgentCallbackLogin() exit*/
2099 if (login_state > 0) {
2100 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
2101 if (login_state==1) {
2102 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
2103 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", args.extension);
2106 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
2110 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
2112 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num)) {
2113 LOCAL_USER_REMOVE(u);
2116 /* Do we need to play agent-goodbye now that we will be hanging up? */
2117 if (play_announcement) {
2119 res = ast_safe_sleep(chan, 1000);
2120 res = ast_streamfile(chan, agent_goodbye, chan->language);
2122 res = ast_waitstream(chan, "");
2124 res = ast_safe_sleep(chan, 1000);
2128 LOCAL_USER_REMOVE(u);
2130 /* We should never get here if next priority exists when in callbackmode */
2135 * Called by the AgentLogin application (from the dial plan).
2140 * @sa callback_login_exec(), agentmonitoroutgoing_exec(), load_module().
2142 static int login_exec(struct ast_channel *chan, void *data)
2144 return __login_exec(chan, data, 0);
2148 * Called by the AgentCallbackLogin application (from the dial plan).
2153 * @sa login_exec(), agentmonitoroutgoing_exec(), load_module().
2155 static int callback_exec(struct ast_channel *chan, void *data)
2157 return __login_exec(chan, data, 1);
2161 * Sets an agent as logged in by callback in the Manager API.
2162 * It is registered on load_module() and it gets called by the manager backend.
2166 * @sa action_agents(), action_agent_logoff(), load_module().
2168 static int action_agent_callback_login(struct mansession *s, struct message *m)
2170 char *agent = astman_get_header(m, "Agent");
2171 char *exten = astman_get_header(m, "Exten");
2172 char *context = astman_get_header(m, "Context");
2173 char *wrapuptime_s = astman_get_header(m, "WrapupTime");
2174 char *ackcall_s = astman_get_header(m, "AckCall");
2175 struct agent_pvt *p;
2176 int login_state = 0;
2178 if (ast_strlen_zero(agent)) {
2179 astman_send_error(s, m, "No agent specified");
2183 if (ast_strlen_zero(exten)) {
2184 astman_send_error(s, m, "No extension specified");
2188 ast_mutex_lock(&agentlock);
2191 if (strcmp(p->agent, agent) || p->pending) {
2196 login_state = 2; /* already logged in (and on the phone)*/
2199 ast_mutex_lock(&p->lock);
2200 login_state = 1; /* Successful Login */
2202 if (ast_strlen_zero(context))
2203 ast_copy_string(p->loginchan, exten, sizeof(p->loginchan));
2205 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", exten, context);
2207 if (!ast_strlen_zero(wrapuptime_s)) {
2208 p->wrapuptime = atoi(wrapuptime_s);
2209 if (p->wrapuptime < 0)
2213 if (ast_true(ackcall_s))
2218 if (p->loginstart == 0)
2219 time(&p->loginstart);
2220 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
2222 "Loginchan: %s\r\n",
2223 p->agent, p->loginchan);
2224 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
2225 if (option_verbose > 1)
2226 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
2227 ast_device_state_changed("Agent/%s", p->agent);
2228 ast_mutex_unlock(&p->lock);
2231 ast_mutex_unlock(&agentlock);
2233 if (login_state == 1)
2234 astman_send_ack(s, m, "Agent logged in");
2235 else if (login_state == 0)
2236 astman_send_error(s, m, "No such agent");
2237 else if (login_state == 2)
2238 astman_send_error(s, m, "Agent already logged in");
2244 * Called by the AgentMonitorOutgoing application (from the dial plan).
2249 * @sa login_exec(), callback_login_exec(), load_module().
2251 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2253 int exitifnoagentid = 0;
2255 int changeoutgoing = 0;
2257 char agent[AST_MAX_AGENT];
2260 if (strchr(data, 'd'))
2261 exitifnoagentid = 1;
2262 if (strchr(data, 'n'))
2264 if (strchr(data, 'c'))
2267 if (chan->cid.cid_num) {
2269 char agentvar[AST_MAX_BUF];
2270 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2271 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2272 struct agent_pvt *p = agents;
2273 ast_copy_string(agent, tmp, sizeof(agent));
2274 ast_mutex_lock(&agentlock);
2276 if (!strcasecmp(p->agent, tmp)) {
2277 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2278 __agent_start_monitoring(chan, p, 1);
2283 ast_mutex_unlock(&agentlock);
2288 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);
2293 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");
2295 /* check if there is n + 101 priority */
2297 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2298 chan->priority+=100;
2299 if (option_verbose > 2)
2300 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2302 else if (exitifnoagentid)
2309 * Dump AgentCallbackLogin agents to the database for persistence
2311 static void dump_agents(void)
2313 struct agent_pvt *cur_agent = NULL;
2316 for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2317 if (cur_agent->chan)
2320 if (!ast_strlen_zero(cur_agent->loginchan)) {
2321 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2322 if (ast_db_put(pa_family, cur_agent->agent, buf))
2323 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2324 else if (option_debug)
2325 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2327 /* Delete - no agent or there is an error */
2328 ast_db_del(pa_family, cur_agent->agent);
2334 * Reload the persistent agents from astdb.
2336 static void reload_agents(void)
2339 struct ast_db_entry *db_tree;
2340 struct ast_db_entry *entry;
2341 struct agent_pvt *cur_agent;
2342 char agent_data[256];
2345 char *agent_callerid;
2347 db_tree = ast_db_gettree(pa_family, NULL);
2349 ast_mutex_lock(&agentlock);
2350 for (entry = db_tree; entry; entry = entry->next) {
2351 agent_num = entry->key + strlen(pa_family) + 2;
2354 ast_mutex_lock(&cur_agent->lock);
2355 if (strcmp(agent_num, cur_agent->agent) == 0)
2357 ast_mutex_unlock(&cur_agent->lock);
2358 cur_agent = cur_agent->next;
2361 ast_db_del(pa_family, agent_num);
2364 ast_mutex_unlock(&cur_agent->lock);
2365 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2367 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2369 agent_chan = strsep(&parse, ";");
2370 agent_callerid = strsep(&parse, ";");
2371 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2372 if (agent_callerid) {
2373 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2374 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2376 cur_agent->logincallerid[0] = '\0';
2377 if (cur_agent->loginstart == 0)
2378 time(&cur_agent->loginstart);
2379 ast_device_state_changed("Agent/%s", cur_agent->agent);
2382 ast_mutex_unlock(&agentlock);
2384 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2385 ast_db_freetree(db_tree);
2389 /*--- agent_devicestate: Part of PBX channel interface ---*/
2390 static int agent_devicestate(void *data)
2392 struct agent_pvt *p;
2394 ast_group_t groupmatch;
2397 int res = AST_DEVICE_INVALID;
2400 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2401 groupmatch = (1 << groupoff);
2402 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2403 groupmatch = (1 << groupoff);
2409 /* Check actual logged in agents first */
2410 ast_mutex_lock(&agentlock);
2413 ast_mutex_lock(&p->lock);
2414 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2416 if (res != AST_DEVICE_INUSE)
2417 res = AST_DEVICE_BUSY;
2419 if (res == AST_DEVICE_BUSY)
2420 res = AST_DEVICE_INUSE;
2421 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2422 if (res == AST_DEVICE_INVALID)
2423 res = AST_DEVICE_UNKNOWN;
2424 } else if (res == AST_DEVICE_INVALID)
2425 res = AST_DEVICE_UNAVAILABLE;
2427 if (!strcmp(data, p->agent)) {
2428 ast_mutex_unlock(&p->lock);
2432 ast_mutex_unlock(&p->lock);
2435 ast_mutex_unlock(&agentlock);
2439 struct agent_pvt *find_agent(char *agentid)
2441 struct agent_pvt *cur = agents;
2443 for (; cur; cur = cur->next) {
2444 if (!strcmp(cur->agent, agentid))
2451 static char *function_agent(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
2456 struct agent_pvt *agent;
2460 if (ast_strlen_zero(data)) {
2461 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2465 item = ast_strdupa(data);
2467 ast_log(LOG_ERROR, "Out of memory!\n");
2471 agentid = strsep(&item, ":");
2475 agent = find_agent(agentid);
2477 ast_log(LOG_WARNING, "Agent '%s' not found!\n", agentid);
2481 if (!strcasecmp(item, "status")) {
2482 if (agent->chan || !ast_strlen_zero(agent->loginchan)) {
2483 ast_copy_string(buf, "LOGGEDIN", len);
2485 ast_copy_string(buf, "LOGGEDOUT", len);
2487 } else if (!strcasecmp(item, "password")) {
2488 ast_copy_string(buf, agent->password, len);
2489 } else if (!strcasecmp(item, "name")) {
2490 ast_copy_string(buf, agent->name, len);
2491 } else if (!strcasecmp(item, "mohclass")) {
2492 ast_copy_string(buf, agent->moh, len);
2493 } else if (!strcasecmp(item, "channel")) {
2495 ast_copy_string(buf, agent->chan->name, len);
2496 tmp = strrchr(buf, '-');
2500 } else if (!strcasecmp(item, "exten")) {
2501 ast_copy_string(buf, agent->loginchan, len);
2507 struct ast_custom_function agent_function = {
2509 .synopsis = "Gets information about an Agent",
2510 .syntax = "AGENT(<agentid>[:item])",
2511 .read = function_agent,
2512 .desc = "The valid items to retrieve are:\n"
2513 "- status (default) The status of the agent\n"
2514 " LOGGEDIN | LOGGEDOUT\n"
2515 "- password The password of the agent\n"
2516 "- name The name of the agent\n"
2517 "- mohclass MusicOnHold class\n"
2518 "- exten The callback extension for the Agent (AgentCallbackLogin)\n"
2519 "- channel The name of the active channel for the Agent (AgentLogin)\n"
2524 * Initialize the Agents module.
2525 * This funcion is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
2527 * @returns int Always 0.
2531 /* Make sure we can register our agent channel type */
2532 if (ast_channel_register(&agent_tech)) {
2533 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2536 /* Dialplan applications */
2537 ast_register_application(app, login_exec, synopsis, descrip);
2538 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2539 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2540 /* Manager commands */
2541 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2542 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2543 ast_manager_register2("AgentCallbackLogin", EVENT_FLAG_AGENT, action_agent_callback_login, "Sets an agent as logged in by callback", mandescr_agent_callback_login);
2545 ast_cli_register(&cli_show_agents);
2546 ast_cli_register(&cli_agent_logoff);
2547 /* Dialplan Functions */
2548 ast_custom_function_register(&agent_function);
2549 /* Read in the config */
2550 read_agent_config();
2551 if (persistent_agents)
2558 read_agent_config();
2559 if (persistent_agents)
2566 struct agent_pvt *p;
2567 /* First, take us out of the channel loop */
2568 /* Unregister dialplan functions */
2569 ast_custom_function_unregister(&agent_function);
2570 /* Unregister CLI commands */
2571 ast_cli_unregister(&cli_show_agents);
2572 ast_cli_unregister(&cli_agent_logoff);
2573 /* Unregister dialplan applications */
2574 ast_unregister_application(app);
2575 ast_unregister_application(app2);
2576 ast_unregister_application(app3);
2577 /* Unregister manager command */
2578 ast_manager_unregister("Agents");
2579 ast_manager_unregister("AgentLogoff");
2580 ast_manager_unregister("AgentCallbackLogin");
2581 /* Unregister channel */
2582 ast_channel_unregister(&agent_tech);
2583 if (!ast_mutex_lock(&agentlock)) {
2584 /* Hangup all interfaces if they have an owner */
2588 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2592 ast_mutex_unlock(&agentlock);
2594 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2607 return ASTERISK_GPL_KEY;
2612 return (char *) desc;