2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, 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
34 <depend>chan_local</depend>
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
41 #include <sys/socket.h>
44 #include <netinet/in.h>
45 #include <arpa/inet.h>
46 #include <sys/signal.h>
48 #include "asterisk/lock.h"
49 #include "asterisk/channel.h"
50 #include "asterisk/config.h"
51 #include "asterisk/module.h"
52 #include "asterisk/pbx.h"
53 #include "asterisk/sched.h"
54 #include "asterisk/io.h"
55 #include "asterisk/rtp.h"
56 #include "asterisk/acl.h"
57 #include "asterisk/callerid.h"
58 #include "asterisk/file.h"
59 #include "asterisk/cli.h"
60 #include "asterisk/app.h"
61 #include "asterisk/musiconhold.h"
62 #include "asterisk/manager.h"
63 #include "asterisk/features.h"
64 #include "asterisk/utils.h"
65 #include "asterisk/causes.h"
66 #include "asterisk/astdb.h"
67 #include "asterisk/devicestate.h"
68 #include "asterisk/monitor.h"
69 #include "asterisk/stringfields.h"
70 #include "asterisk/event.h"
72 static const char tdesc[] = "Call Agent Proxy Channel";
73 static const char config[] = "agents.conf";
75 static const char app[] = "AgentLogin";
76 static const char app3[] = "AgentMonitorOutgoing";
78 static const char synopsis[] = "Call agent login";
79 static const char synopsis3[] = "Record agent's outgoing call";
81 static const char descrip[] =
82 " AgentLogin([AgentNo][,options]):\n"
83 "Asks the agent to login to the system. Always returns -1. While\n"
84 "logged in, the agent can receive calls and will hear a 'beep'\n"
85 "when a new call comes in. The agent can dump the call by pressing\n"
87 "The option string may contain zero or more of the following characters:\n"
88 " 's' -- silent login - do not announce the login ok segment after agent logged on/off\n";
90 static const char descrip3[] =
91 " AgentMonitorOutgoing([options]):\n"
92 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
93 "comparison of the callerid of the current interface and the global variable \n"
94 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
95 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
96 "instead of Monitor application. That has to be configured in the agents.conf file.\n"
98 "Normally the app returns 0 unless the options are passed.\n"
100 " 'd' - make the app return -1 if there is an error condition\n"
101 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
102 " 'n' - don't generate the warnings when there is no callerid or the\n"
103 " agentid is not known.\n"
104 " It's handy if you want to have one context for agent and non-agent calls.\n";
106 static const char mandescr_agents[] =
107 "Description: Will list info about all possible agents.\n"
110 static const char mandescr_agent_logoff[] =
111 "Description: Sets an agent as no longer logged in.\n"
112 "Variables: (Names marked with * are required)\n"
113 " *Agent: Agent ID of the agent to log off\n"
114 " Soft: Set to 'true' to not hangup existing calls\n";
116 static char moh[80] = "default";
118 #define AST_MAX_AGENT 80 /*!< Agent ID or Password max length */
119 #define AST_MAX_BUF 256
120 #define AST_MAX_FILENAME_LEN 256
122 static const char pa_family[] = "Agents"; /*!< Persistent Agents astdb family */
123 #define PA_MAX_LEN 2048 /*!< The maximum length of each persistent member agent database entry */
125 static int persistent_agents = 0; /*!< queues.conf [general] option */
126 static void dump_agents(void);
128 #define DEFAULT_ACCEPTDTMF '#'
129 #define DEFAULT_ENDDTMF '*'
131 static ast_group_t group;
132 static int autologoff;
133 static int wrapuptime;
136 static int multiplelogin = 1;
137 static int autologoffunavail = 0;
138 static char acceptdtmf = DEFAULT_ACCEPTDTMF;
139 static char enddtmf = DEFAULT_ENDDTMF;
141 static int maxlogintries = 3;
142 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
144 static int recordagentcalls = 0;
145 static char recordformat[AST_MAX_BUF] = "";
146 static char recordformatext[AST_MAX_BUF] = "";
147 static char urlprefix[AST_MAX_BUF] = "";
148 static char savecallsin[AST_MAX_BUF] = "";
149 static int updatecdr = 0;
150 static char beep[AST_MAX_BUF] = "beep";
151 struct ast_event_sub *agent_devicestate_sub = NULL;
153 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
155 /*! \brief Structure representing an agent. */
157 ast_mutex_t lock; /*!< Channel private lock */
158 int dead; /*!< Poised for destruction? */
159 int pending; /*!< Not a real agent -- just pending a match */
160 int abouttograb; /*!< About to grab */
161 int autologoff; /*!< Auto timeout time */
162 int ackcall; /*!< ackcall */
163 int deferlogoff; /*!< Defer logoff to hangup */
166 time_t loginstart; /*!< When agent first logged in (0 when logged off) */
167 time_t start; /*!< When call started */
168 struct timeval lastdisc; /*!< When last disconnected */
169 int wrapuptime; /*!< Wrapup time in ms */
170 ast_group_t group; /*!< Group memberships */
171 int acknowledged; /*!< Acknowledged */
172 char moh[80]; /*!< Which music on hold */
173 char agent[AST_MAX_AGENT]; /*!< Agent ID */
174 char password[AST_MAX_AGENT]; /*!< Password for Agent login */
175 char name[AST_MAX_AGENT];
176 int inherited_devicestate; /*!< Does the underlying channel have a devicestate to pass? */
177 ast_mutex_t app_lock; /**< Synchronization between owning applications */
178 volatile pthread_t owning_app; /**< Owning application thread id */
179 volatile int app_sleep_cond; /**< Sleep condition for the login app */
180 struct ast_channel *owner; /**< Agent */
181 char loginchan[80]; /**< channel they logged in from */
182 char logincallerid[80]; /**< Caller ID they had when they logged in */
183 struct ast_channel *chan; /**< Channel we use */
184 AST_LIST_ENTRY(agent_pvt) list; /**< Next Agent in the linked list. */
187 static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (loaded form agents.conf). */
189 #define CHECK_FORMATS(ast, p) do { \
191 if (ast->nativeformats != p->chan->nativeformats) { \
192 ast_debug(1, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
193 /* Native formats changed, reset things */ \
194 ast->nativeformats = p->chan->nativeformats; \
195 ast_debug(1, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
196 ast_set_read_format(ast, ast->readformat); \
197 ast_set_write_format(ast, ast->writeformat); \
199 if (p->chan->readformat != ast->rawreadformat && !p->chan->generator) \
200 ast_set_read_format(p->chan, ast->rawreadformat); \
201 if (p->chan->writeformat != ast->rawwriteformat && !p->chan->generator) \
202 ast_set_write_format(p->chan, ast->rawwriteformat); \
206 /*! \brief Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
207 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
208 totally impractical combinations XXX */
210 #define CLEANUP(ast, p) do { \
213 for (x=0;x<AST_MAX_FDS;x++) {\
214 if (x != AST_TIMING_FD) \
215 ast_channel_set_fd(ast, x, p->chan->fds[x]); \
217 ast_channel_set_fd(ast, AST_AGENT_FD, p->chan->fds[AST_TIMING_FD]); \
221 /*--- Forward declarations */
222 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
223 static int agent_devicestate(void *data);
224 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand);
225 static int agent_digit_begin(struct ast_channel *ast, char digit);
226 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
227 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
228 static int agent_hangup(struct ast_channel *ast);
229 static int agent_answer(struct ast_channel *ast);
230 static struct ast_frame *agent_read(struct ast_channel *ast);
231 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
232 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
233 static int agent_sendtext(struct ast_channel *ast, const char *text);
234 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
235 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
236 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
237 static void set_agentbycallerid(const char *callerid, const char *agent);
238 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state);
239 static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
240 static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base);
242 /*! \brief Channel interface description for PBX integration */
243 static const struct ast_channel_tech agent_tech = {
245 .description = tdesc,
247 .requester = agent_request,
248 .devicestate = agent_devicestate,
249 .send_digit_begin = agent_digit_begin,
250 .send_digit_end = agent_digit_end,
252 .hangup = agent_hangup,
253 .answer = agent_answer,
255 .write = agent_write,
256 .write_video = agent_write,
257 .send_html = agent_sendhtml,
258 .send_text = agent_sendtext,
259 .exception = agent_read,
260 .indicate = agent_indicate,
261 .fixup = agent_fixup,
262 .bridged_channel = agent_bridgedchannel,
263 .get_base_channel = agent_get_base_channel,
264 .set_base_channel = agent_set_base_channel,
267 static void agent_devicestate_cb(const struct ast_event *event, void *unused)
271 char basename[AST_CHANNEL_NAME], *tmp;
273 enum ast_device_state state;
275 state = ast_event_get_ie_uint(event, AST_EVENT_IE_STATE);
276 device = ast_event_get_ie_str(event, AST_EVENT_IE_DEVICE);
278 if (ast_strlen_zero(device)) {
282 /* Skip Agent status */
283 if (!strncasecmp(device, "Agent/", 6)) {
287 /* Try to be safe, but don't deadlock */
288 for (i = 0; i < 10; i++) {
289 if ((res = AST_LIST_TRYLOCK(&agents)) == 0) {
297 AST_LIST_TRAVERSE(&agents, p, list) {
298 ast_mutex_lock(&p->lock);
300 ast_copy_string(basename, p->chan->name, sizeof(basename));
301 if ((tmp = strrchr(basename, '-'))) {
304 if (strcasecmp(p->chan->name, device) == 0 || strcasecmp(basename, device) == 0) {
305 p->inherited_devicestate = state;
306 ast_devstate_changed(state, "Agent/%s", p->agent);
309 ast_mutex_unlock(&p->lock);
311 AST_LIST_UNLOCK(&agents);
315 * Adds an agent to the global list of agents.
317 * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
318 * \param pending If it is pending or not.
319 * @return The just created agent.
320 * \sa agent_pvt, agents.
322 static struct agent_pvt *add_agent(const char *agent, int pending)
325 AST_DECLARE_APP_ARGS(args,
327 AST_APP_ARG(password);
330 char *password = NULL;
335 parse = ast_strdupa(agent);
337 /* Extract username (agt), password and name from agent (args). */
338 AST_STANDARD_APP_ARGS(args, parse);
341 ast_log(LOG_WARNING, "A blank agent line!\n");
345 if(ast_strlen_zero(args.agt) ) {
346 ast_log(LOG_WARNING, "An agent line with no agentid!\n");
351 if(!ast_strlen_zero(args.password)) {
352 password = args.password;
353 while (*password && *password < 33) password++;
355 if(!ast_strlen_zero(args.name)) {
357 while (*name && *name < 33) name++;
360 /* Are we searching for the agent here ? To see if it exists already ? */
361 AST_LIST_TRAVERSE(&agents, p, list) {
362 if (!pending && !strcmp(p->agent, agt))
367 if (!(p = ast_calloc(1, sizeof(*p))))
369 ast_copy_string(p->agent, agt, sizeof(p->agent));
370 ast_mutex_init(&p->lock);
371 ast_mutex_init(&p->app_lock);
372 p->owning_app = (pthread_t) -1;
373 p->app_sleep_cond = 1;
375 p->pending = pending;
376 p->inherited_devicestate = -1;
377 AST_LIST_INSERT_TAIL(&agents, p, list);
380 ast_copy_string(p->password, password ? password : "", sizeof(p->password));
381 ast_copy_string(p->name, name ? name : "", sizeof(p->name));
382 ast_copy_string(p->moh, moh, sizeof(p->moh));
383 p->ackcall = ackcall;
384 p->autologoff = autologoff;
385 p->acceptdtmf = acceptdtmf;
386 p->enddtmf = enddtmf;
388 /* If someone reduces the wrapuptime and reloads, we want it
389 * to change the wrapuptime immediately on all calls */
390 if (p->wrapuptime > wrapuptime) {
391 struct timeval now = ast_tvnow();
392 /* XXX check what is this exactly */
394 /* We won't be pedantic and check the tv_usec val */
395 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
396 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
397 p->lastdisc.tv_usec = now.tv_usec;
400 p->wrapuptime = wrapuptime;
410 * Deletes an agent after doing some clean up.
411 * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
412 * \param p Agent to be deleted.
415 static int agent_cleanup(struct agent_pvt *p)
417 struct ast_channel *chan = p->owner;
419 chan->tech_pvt = NULL;
420 p->app_sleep_cond = 1;
421 /* Release ownership of the agent to other threads (presumably running the login app). */
422 ast_mutex_unlock(&p->app_lock);
424 ast_channel_free(chan);
426 ast_mutex_destroy(&p->lock);
427 ast_mutex_destroy(&p->app_lock);
433 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
435 static int agent_answer(struct ast_channel *ast)
437 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
441 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
443 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
444 char filename[AST_MAX_BUF];
449 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
450 /* substitute . for - */
451 if ((pointer = strchr(filename, '.')))
453 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
454 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
455 ast_monitor_setjoinfiles(ast, 1);
456 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
458 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
461 ast->cdr = ast_cdr_alloc();
462 ast_cdr_setuserfield(ast, tmp2);
465 ast_log(LOG_ERROR, "Recording already started on that call.\n");
469 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
471 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
474 static struct ast_frame *agent_read(struct ast_channel *ast)
476 struct agent_pvt *p = ast->tech_pvt;
477 struct ast_frame *f = NULL;
478 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
480 ast_mutex_lock(&p->lock);
481 CHECK_FORMATS(ast, p);
483 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
484 p->chan->fdno = (ast->fdno == AST_AGENT_FD) ? AST_TIMING_FD : ast->fdno;
485 f = ast_read(p->chan);
489 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
491 p->chan->_bridge = NULL;
492 /* Note that we don't hangup if it's not a callback because Asterisk will do it
493 for us when the PBX instance that called login finishes */
494 if (!ast_strlen_zero(p->loginchan)) {
496 ast_debug(1, "Bridge on '%s' being cleared (2)\n", p->chan->name);
497 if (p->owner->_state != AST_STATE_UP) {
498 int howlong = time(NULL) - p->start;
499 if (p->autologoff && howlong > p->autologoff) {
500 long logintime = time(NULL) - p->loginstart;
502 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
503 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
504 if (persistent_agents)
508 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
509 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
510 long logintime = time(NULL) - p->loginstart;
512 ast_log(LOG_NOTICE, "Agent read: '%s' is not available now, auto logoff\n", p->name);
513 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
516 if (p->wrapuptime && p->acknowledged)
517 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
520 p->inherited_devicestate = -1;
521 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
525 /* if acknowledgement is not required, and the channel is up, we may have missed
526 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
527 if (!p->ackcall && !p->acknowledged && p->chan && (p->chan->_state == AST_STATE_UP))
529 switch (f->frametype) {
530 case AST_FRAME_CONTROL:
531 if (f->subclass == AST_CONTROL_ANSWER) {
533 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", p->chan->name, p->acceptdtmf);
534 /* Don't pass answer along */
539 /* Use the builtin answer frame for the
540 recording start check below. */
546 case AST_FRAME_DTMF_BEGIN:
547 /*ignore DTMF begin's as it can cause issues with queue announce files*/
548 if((!p->acknowledged && f->subclass == p->acceptdtmf) || (f->subclass == p->enddtmf && endcall)){
553 case AST_FRAME_DTMF_END:
554 if (!p->acknowledged && (f->subclass == p->acceptdtmf)) {
555 ast_verb(3, "%s acknowledged\n", p->chan->name);
559 } else if (f->subclass == p->enddtmf && endcall) {
560 /* terminates call */
565 case AST_FRAME_VOICE:
566 case AST_FRAME_VIDEO:
567 /* don't pass voice or video until the call is acknowledged */
568 if (!p->acknowledged) {
573 /* pass everything else on through */
579 if (p->chan && !p->chan->_bridge) {
580 if (strcasecmp(p->chan->tech->type, "Local")) {
581 p->chan->_bridge = ast;
583 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
586 ast_mutex_unlock(&p->lock);
587 if (recordagentcalls && f == &answer_frame)
588 agent_start_monitoring(ast,0);
592 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
594 struct agent_pvt *p = ast->tech_pvt;
596 ast_mutex_lock(&p->lock);
598 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
599 ast_mutex_unlock(&p->lock);
603 static int agent_sendtext(struct ast_channel *ast, const char *text)
605 struct agent_pvt *p = ast->tech_pvt;
607 ast_mutex_lock(&p->lock);
609 res = ast_sendtext(p->chan, text);
610 ast_mutex_unlock(&p->lock);
614 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
616 struct agent_pvt *p = ast->tech_pvt;
618 CHECK_FORMATS(ast, p);
619 ast_mutex_lock(&p->lock);
623 if ((f->frametype != AST_FRAME_VOICE) ||
624 (f->frametype != AST_FRAME_VIDEO) ||
625 (f->subclass == p->chan->writeformat)) {
626 res = ast_write(p->chan, f);
628 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n",
629 f->frametype == AST_FRAME_VOICE ? "audio" : "video",
630 ast->name, p->chan->name);
635 ast_mutex_unlock(&p->lock);
639 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
641 struct agent_pvt *p = newchan->tech_pvt;
642 ast_mutex_lock(&p->lock);
643 if (p->owner != oldchan) {
644 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
645 ast_mutex_unlock(&p->lock);
649 ast_mutex_unlock(&p->lock);
653 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
655 struct agent_pvt *p = ast->tech_pvt;
657 ast_mutex_lock(&p->lock);
659 res = p->chan->tech->indicate ? p->chan->tech->indicate(p->chan, condition, data, datalen) : -1;
662 ast_mutex_unlock(&p->lock);
666 static int agent_digit_begin(struct ast_channel *ast, char digit)
668 struct agent_pvt *p = ast->tech_pvt;
669 ast_mutex_lock(&p->lock);
671 ast_senddigit_begin(p->chan, digit);
673 ast_mutex_unlock(&p->lock);
677 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
679 struct agent_pvt *p = ast->tech_pvt;
680 ast_mutex_lock(&p->lock);
682 ast_senddigit_end(p->chan, digit, duration);
684 ast_mutex_unlock(&p->lock);
688 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
690 struct agent_pvt *p = ast->tech_pvt;
693 ast_mutex_lock(&p->lock);
697 ast_debug(1, "Pretending to dial on pending agent\n");
698 newstate = AST_STATE_DIALING;
701 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
704 ast_mutex_unlock(&p->lock);
706 ast_setstate(ast, newstate);
708 } else if (!ast_strlen_zero(p->loginchan)) {
710 /* Call on this agent */
711 ast_verb(3, "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
712 ast_set_callerid(p->chan,
713 ast->cid.cid_num, ast->cid.cid_name, NULL);
714 ast_channel_inherit_variables(ast, p->chan);
715 res = ast_call(p->chan, p->loginchan, 0);
717 ast_mutex_unlock(&p->lock);
720 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
721 ast_debug(3, "Playing beep, lang '%s'\n", p->chan->language);
722 res = ast_streamfile(p->chan, beep, p->chan->language);
723 ast_debug(3, "Played beep, result '%d'\n", res);
725 res = ast_waitstream(p->chan, "");
726 ast_debug(3, "Waited for stream, result '%d'\n", res);
729 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
730 ast_debug(3, "Set read format, result '%d'\n", res);
732 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
736 p->inherited_devicestate = -1;
737 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
741 res = ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
742 ast_debug(3, "Set write format, result '%d'\n", res);
744 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
747 /* Call is immediately up, or might need ack */
749 newstate = AST_STATE_RINGING;
751 newstate = AST_STATE_UP;
752 if (recordagentcalls)
753 agent_start_monitoring(ast, 0);
759 ast_mutex_unlock(&p->lock);
761 ast_setstate(ast, newstate);
765 /*! \brief store/clear the global variable that stores agentid based on the callerid */
766 static void set_agentbycallerid(const char *callerid, const char *agent)
768 char buf[AST_MAX_BUF];
770 /* if there is no Caller ID, nothing to do */
771 if (ast_strlen_zero(callerid))
774 snprintf(buf, sizeof(buf), "%s_%s", GETAGENTBYCALLERID, callerid);
775 pbx_builtin_setvar_helper(NULL, buf, agent);
778 /*! \brief return the channel or base channel if one exists. This function assumes the channel it is called on is already locked */
779 struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
781 struct agent_pvt *p = NULL;
782 struct ast_channel *base = chan;
784 /* chan is locked by the calling function */
785 if (!chan || !chan->tech_pvt) {
786 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) with a tech_pvt (0x%ld) to get a base channel.\n", (long)chan, (chan)?(long)chan->tech_pvt:(long)NULL);
795 int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
797 struct agent_pvt *p = NULL;
799 if (!chan || !base) {
800 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
805 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", chan->name);
812 static int agent_hangup(struct ast_channel *ast)
814 struct agent_pvt *p = ast->tech_pvt;
817 ast_mutex_lock(&p->lock);
819 ast->tech_pvt = NULL;
820 p->app_sleep_cond = 1;
823 /* if they really are hung up then set start to 0 so the test
824 * later if we're called on an already downed channel
825 * doesn't cause an agent to be logged out like when
826 * agent_request() is followed immediately by agent_hangup()
827 * as in apps/app_chanisavail.c:chanavail_exec()
830 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast->_state));
831 if (p->start && (ast->_state != AST_STATE_UP)) {
832 howlong = time(NULL) - p->start;
834 } else if (ast->_state == AST_STATE_RESERVED)
839 p->chan->_bridge = NULL;
840 /* If they're dead, go ahead and hang up on the agent now */
841 if (!ast_strlen_zero(p->loginchan)) {
842 /* Store last disconnect time */
844 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
846 p->lastdisc = ast_tv(0,0);
848 status = pbx_builtin_getvar_helper(p->chan, "CHANLOCALSTATUS");
849 if (autologoffunavail && status && !strcasecmp(status, "CHANUNAVAIL")) {
850 long logintime = time(NULL) - p->loginstart;
852 ast_log(LOG_NOTICE, "Agent hangup: '%s' is not available now, auto logoff\n", p->name);
853 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Chanunavail");
855 /* Recognize the hangup and pass it along immediately */
858 p->inherited_devicestate = -1;
859 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
861 ast_debug(1, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
862 if ((p->deferlogoff) || (howlong && p->autologoff && (howlong > p->autologoff))) {
863 long logintime = time(NULL) - p->loginstart;
866 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
868 agent_logoff_maintenance(p, p->loginchan, logintime, ast->uniqueid, "Autologoff");
869 if (persistent_agents)
872 } else if (p->dead) {
873 ast_channel_lock(p->chan);
874 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
875 ast_channel_unlock(p->chan);
876 } else if (p->loginstart) {
877 ast_channel_lock(p->chan);
878 ast_indicate_data(p->chan, AST_CONTROL_HOLD,
880 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
881 ast_channel_unlock(p->chan);
884 ast_mutex_unlock(&p->lock);
886 /* Only register a device state change if the agent is still logged in */
887 if (!p->loginstart) {
888 p->loginchan[0] = '\0';
889 p->logincallerid[0] = '\0';
890 if (persistent_agents)
893 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
897 AST_LIST_LOCK(&agents);
898 AST_LIST_REMOVE(&agents, p, list);
899 AST_LIST_UNLOCK(&agents);
901 if (p->abouttograb) {
902 /* Let the "about to grab" thread know this isn't valid anymore, and let it
905 } else if (p->dead) {
906 ast_mutex_destroy(&p->lock);
907 ast_mutex_destroy(&p->app_lock);
911 /* Not dead -- check availability now */
912 ast_mutex_lock(&p->lock);
913 /* Store last disconnect time */
914 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
915 ast_mutex_unlock(&p->lock);
917 /* Release ownership of the agent to other threads (presumably running the login app). */
918 if (ast_strlen_zero(p->loginchan))
919 ast_mutex_unlock(&p->app_lock);
924 static int agent_cont_sleep( void *data )
929 p = (struct agent_pvt *)data;
931 ast_mutex_lock(&p->lock);
932 res = p->app_sleep_cond;
933 if (p->lastdisc.tv_sec) {
934 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0)
937 ast_mutex_unlock(&p->lock);
940 ast_debug(5, "agent_cont_sleep() returning %d\n", res );
945 static int agent_ack_sleep(void *data)
952 /* Wait a second and look for something */
954 p = (struct agent_pvt *) data;
959 to = ast_waitfor(p->chan, to);
964 f = ast_read(p->chan);
967 if (f->frametype == AST_FRAME_DTMF)
972 ast_mutex_lock(&p->lock);
973 if (!p->app_sleep_cond) {
974 ast_mutex_unlock(&p->lock);
976 } else if (res == p->acceptdtmf) {
977 ast_mutex_unlock(&p->lock);
980 ast_mutex_unlock(&p->lock);
986 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
988 struct agent_pvt *p = bridge->tech_pvt;
989 struct ast_channel *ret = NULL;
993 ret = bridge->_bridge;
994 else if (chan == bridge->_bridge)
998 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
1002 /*! \brief Create new agent channel */
1003 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
1005 struct ast_channel *tmp;
1008 ast_log(LOG_WARNING, "No channel? :(\n");
1013 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/P%s-%d", p->agent, ast_random() & 0xffff);
1015 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? p->chan->exten:"", p->chan ? p->chan->context:"", 0, "Agent/%s", p->agent);
1017 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
1021 tmp->tech = &agent_tech;
1023 tmp->nativeformats = p->chan->nativeformats;
1024 tmp->writeformat = p->chan->writeformat;
1025 tmp->rawwriteformat = p->chan->writeformat;
1026 tmp->readformat = p->chan->readformat;
1027 tmp->rawreadformat = p->chan->readformat;
1028 ast_string_field_set(tmp, language, p->chan->language);
1029 ast_copy_string(tmp->context, p->chan->context, sizeof(tmp->context));
1030 ast_copy_string(tmp->exten, p->chan->exten, sizeof(tmp->exten));
1031 /* XXX Is this really all we copy form the originating channel?? */
1033 tmp->nativeformats = AST_FORMAT_SLINEAR;
1034 tmp->writeformat = AST_FORMAT_SLINEAR;
1035 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
1036 tmp->readformat = AST_FORMAT_SLINEAR;
1037 tmp->rawreadformat = AST_FORMAT_SLINEAR;
1039 /* Safe, agentlock already held */
1043 /* Wake up and wait for other applications (by definition the login app)
1044 * to release this channel). Takes ownership of the agent channel
1045 * to this thread only.
1046 * For signalling the other thread, ast_queue_frame is used until we
1047 * can safely use signals for this purpose. The pselect() needs to be
1048 * implemented in the kernel for this.
1050 p->app_sleep_cond = 0;
1051 if(ast_strlen_zero(p->loginchan) && ast_mutex_trylock(&p->app_lock)) {
1053 ast_queue_frame(p->chan, &ast_null_frame);
1054 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
1055 ast_mutex_lock(&p->app_lock);
1056 ast_mutex_lock(&p->lock);
1058 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
1060 tmp->tech_pvt = NULL;
1061 p->app_sleep_cond = 1;
1062 ast_channel_free( tmp );
1063 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
1064 ast_mutex_unlock(&p->app_lock);
1067 } else if (!ast_strlen_zero(p->loginchan)) {
1069 ast_queue_frame(p->chan, &ast_null_frame);
1071 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
1073 tmp->tech_pvt = NULL;
1074 p->app_sleep_cond = 1;
1075 ast_channel_free( tmp );
1076 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
1081 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
1082 p->owning_app = pthread_self();
1083 /* After the above step, there should not be any blockers. */
1085 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
1086 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
1087 ast_assert(ast_test_flag(p->chan, AST_FLAG_BLOCKING) == 0);
1095 * Read configuration data. The file named agents.conf.
1097 * \returns Always 0, or so it seems.
1099 static int read_agent_config(int reload)
1101 struct ast_config *cfg;
1102 struct ast_config *ucfg;
1103 struct ast_variable *v;
1104 struct agent_pvt *p;
1105 const char *general_val;
1106 const char *catname;
1107 const char *hasagent;
1109 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1116 cfg = ast_config_load(config, config_flags);
1118 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1120 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
1122 AST_LIST_LOCK(&agents);
1123 AST_LIST_TRAVERSE(&agents, p, list) {
1126 strcpy(moh, "default");
1127 /* set the default recording values */
1128 recordagentcalls = 0;
1129 strcpy(recordformat, "wav");
1130 strcpy(recordformatext, "wav");
1131 urlprefix[0] = '\0';
1132 savecallsin[0] = '\0';
1134 /* Read in [general] section for persistence */
1135 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1136 persistent_agents = ast_true(general_val);
1137 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1139 /* Read in the [agents] section */
1140 v = ast_variable_browse(cfg, "agents");
1142 /* Create the interface list */
1143 if (!strcasecmp(v->name, "agent")) {
1144 add_agent(v->value, 0);
1145 } else if (!strcasecmp(v->name, "group")) {
1146 group = ast_get_group(v->value);
1147 } else if (!strcasecmp(v->name, "autologoff")) {
1148 autologoff = atoi(v->value);
1151 } else if (!strcasecmp(v->name, "ackcall")) {
1152 if (!strcasecmp(v->value, "always"))
1154 else if (ast_true(v->value))
1158 } else if (!strcasecmp(v->name, "endcall")) {
1159 endcall = ast_true(v->value);
1160 } else if (!strcasecmp(v->name, "acceptdtmf")) {
1161 acceptdtmf = *(v->value);
1162 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
1163 } else if (!strcasecmp(v->name, "enddtmf")) {
1164 enddtmf = *(v->value);
1165 } else if (!strcasecmp(v->name, "wrapuptime")) {
1166 wrapuptime = atoi(v->value);
1169 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1170 maxlogintries = atoi(v->value);
1171 if (maxlogintries < 0)
1173 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1174 strcpy(agentgoodbye,v->value);
1175 } else if (!strcasecmp(v->name, "musiconhold")) {
1176 ast_copy_string(moh, v->value, sizeof(moh));
1177 } else if (!strcasecmp(v->name, "updatecdr")) {
1178 if (ast_true(v->value))
1182 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1183 if (ast_true(v->value))
1184 autologoffunavail = 1;
1186 autologoffunavail = 0;
1187 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1188 recordagentcalls = ast_true(v->value);
1189 } else if (!strcasecmp(v->name, "recordformat")) {
1190 ast_copy_string(recordformat, v->value, sizeof(recordformat));
1191 if (!strcasecmp(v->value, "wav49"))
1192 strcpy(recordformatext, "WAV");
1194 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1195 } else if (!strcasecmp(v->name, "urlprefix")) {
1196 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1197 if (urlprefix[strlen(urlprefix) - 1] != '/')
1198 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1199 } else if (!strcasecmp(v->name, "savecallsin")) {
1200 if (v->value[0] == '/')
1201 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1203 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1204 if (savecallsin[strlen(savecallsin) - 1] != '/')
1205 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1206 } else if (!strcasecmp(v->name, "custom_beep")) {
1207 ast_copy_string(beep, v->value, sizeof(beep));
1211 if ((ucfg = ast_config_load("users.conf", config_flags)) && ucfg != CONFIG_STATUS_FILEUNCHANGED) {
1212 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1213 catname = ast_category_browse(ucfg, NULL);
1215 if (strcasecmp(catname, "general")) {
1216 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1217 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1219 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1220 const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1225 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1229 catname = ast_category_browse(ucfg, catname);
1231 ast_config_destroy(ucfg);
1233 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1235 AST_LIST_REMOVE_CURRENT(list);
1236 /* Destroy if appropriate */
1239 ast_mutex_destroy(&p->lock);
1240 ast_mutex_destroy(&p->app_lock);
1243 /* Cause them to hang up */
1244 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1249 AST_LIST_TRAVERSE_SAFE_END;
1250 AST_LIST_UNLOCK(&agents);
1251 ast_config_destroy(cfg);
1255 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1257 struct ast_channel *chan=NULL, *parent=NULL;
1258 struct agent_pvt *p;
1261 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
1263 AST_LIST_LOCK(&agents);
1264 AST_LIST_TRAVERSE(&agents, p, list) {
1265 if (p == newlyavailable) {
1268 ast_mutex_lock(&p->lock);
1269 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1270 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1271 /* We found a pending call, time to merge */
1272 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1275 ast_mutex_unlock(&p->lock);
1278 ast_mutex_unlock(&p->lock);
1281 AST_LIST_UNLOCK(&agents);
1282 if (parent && chan) {
1283 if (newlyavailable->ackcall > 1) {
1284 /* Don't do beep here */
1287 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1288 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1289 ast_debug(3, "Played beep, result '%d'\n", res);
1291 res = ast_waitstream(newlyavailable->chan, "");
1292 ast_debug(1, "Waited for stream, result '%d'\n", res);
1296 /* Note -- parent may have disappeared */
1297 if (p->abouttograb) {
1298 newlyavailable->acknowledged = 1;
1299 /* Safe -- agent lock already held */
1300 ast_setstate(parent, AST_STATE_UP);
1301 ast_setstate(chan, AST_STATE_UP);
1302 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1303 /* Go ahead and mark the channel as a zombie so that masquerade will
1304 destroy it for us, and we need not call ast_hangup */
1305 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1306 ast_channel_masquerade(parent, chan);
1309 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1310 agent_cleanup(newlyavailable);
1313 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n");
1314 agent_cleanup(newlyavailable);
1320 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1322 struct agent_pvt *p;
1325 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1327 AST_LIST_LOCK(&agents);
1328 AST_LIST_TRAVERSE(&agents, p, list) {
1329 if (p == newlyavailable) {
1332 ast_mutex_lock(&p->lock);
1333 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1334 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1335 ast_mutex_unlock(&p->lock);
1338 ast_mutex_unlock(&p->lock);
1341 AST_LIST_UNLOCK(&agents);
1343 ast_mutex_unlock(&newlyavailable->lock);
1344 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1345 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1346 ast_debug(1, "Played beep, result '%d'\n", res);
1348 res = ast_waitstream(newlyavailable->chan, "");
1349 ast_debug(1, "Waited for stream, result '%d'\n", res);
1351 ast_mutex_lock(&newlyavailable->lock);
1356 /*! \brief Part of the Asterisk PBX interface */
1357 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1359 struct agent_pvt *p;
1360 struct ast_channel *chan = NULL;
1362 ast_group_t groupmatch;
1369 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1370 groupmatch = (1 << groupoff);
1371 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1372 groupmatch = (1 << groupoff);
1377 /* Check actual logged in agents first */
1378 AST_LIST_LOCK(&agents);
1379 AST_LIST_TRAVERSE(&agents, p, list) {
1380 ast_mutex_lock(&p->lock);
1381 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1382 ast_strlen_zero(p->loginchan)) {
1386 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
1387 p->lastdisc = ast_tv(0, 0);
1388 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1389 if (!p->owner && p->chan) {
1391 chan = agent_new(p, AST_STATE_DOWN);
1394 ast_mutex_unlock(&p->lock);
1399 ast_mutex_unlock(&p->lock);
1402 AST_LIST_TRAVERSE(&agents, p, list) {
1403 ast_mutex_lock(&p->lock);
1404 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1405 if (p->chan || !ast_strlen_zero(p->loginchan))
1409 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1411 if (!p->lastdisc.tv_sec || (tv.tv_sec >= p->lastdisc.tv_sec)) {
1412 p->lastdisc = ast_tv(0, 0);
1413 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1414 if (!p->owner && p->chan) {
1415 /* Could still get a fixed agent */
1416 chan = agent_new(p, AST_STATE_DOWN);
1417 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1418 /* Adjustable agent */
1419 p->chan = ast_request("Local", format, p->loginchan, cause);
1421 chan = agent_new(p, AST_STATE_DOWN);
1424 ast_mutex_unlock(&p->lock);
1429 ast_mutex_unlock(&p->lock);
1433 if (!chan && waitforagent) {
1434 /* No agent available -- but we're requesting to wait for one.
1435 Allocate a place holder */
1437 ast_debug(1, "Creating place holder for '%s'\n", s);
1438 p = add_agent(data, 1);
1439 p->group = groupmatch;
1440 chan = agent_new(p, AST_STATE_DOWN);
1442 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1444 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1447 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1448 AST_LIST_UNLOCK(&agents);
1452 static force_inline int powerof(unsigned int d)
1463 * Lists agents and their status to the Manager API.
1464 * It is registered on load_module() and it gets called by the manager backend.
1468 * \sa action_agent_logoff(), load_module().
1470 static int action_agents(struct mansession *s, const struct message *m)
1472 const char *id = astman_get_header(m,"ActionID");
1473 char idText[256] = "";
1475 struct agent_pvt *p;
1476 char *username = NULL;
1477 char *loginChan = NULL;
1478 char *talkingto = NULL;
1479 char *talkingtoChan = NULL;
1480 char *status = NULL;
1482 if (!ast_strlen_zero(id))
1483 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1484 astman_send_ack(s, m, "Agents will follow");
1485 AST_LIST_LOCK(&agents);
1486 AST_LIST_TRAVERSE(&agents, p, list) {
1487 ast_mutex_lock(&p->lock);
1490 AGENT_LOGGEDOFF - Agent isn't logged in
1491 AGENT_IDLE - Agent is logged in, and waiting for call
1492 AGENT_ONCALL - Agent is logged in, and on a call
1493 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1495 username = S_OR(p->name, "None");
1497 /* Set a default status. It 'should' get changed. */
1498 status = "AGENT_UNKNOWN";
1500 if (!ast_strlen_zero(p->loginchan) && !p->chan) {
1501 loginChan = p->loginchan;
1503 talkingtoChan = "n/a";
1504 status = "AGENT_IDLE";
1505 if (p->acknowledged) {
1506 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
1507 loginChan = chanbuf;
1509 } else if (p->chan) {
1510 loginChan = ast_strdupa(p->chan->name);
1511 if (p->owner && p->owner->_bridge) {
1512 talkingto = p->chan->cid.cid_num;
1513 if (ast_bridged_channel(p->owner))
1514 talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name);
1516 talkingtoChan = "n/a";
1517 status = "AGENT_ONCALL";
1520 talkingtoChan = "n/a";
1521 status = "AGENT_IDLE";
1526 talkingtoChan = "n/a";
1527 status = "AGENT_LOGGEDOFF";
1530 astman_append(s, "Event: Agents\r\n"
1534 "LoggedInChan: %s\r\n"
1535 "LoggedInTime: %d\r\n"
1537 "TalkingToChan: %s\r\n"
1540 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1541 ast_mutex_unlock(&p->lock);
1543 AST_LIST_UNLOCK(&agents);
1544 astman_append(s, "Event: AgentsComplete\r\n"
1550 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
1553 char agent[AST_MAX_AGENT];
1555 if (!ast_strlen_zero(logcommand))
1558 tmp = ast_strdupa("");
1560 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1562 if (!ast_strlen_zero(uniqueid)) {
1563 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1567 "Logintime: %ld\r\n"
1569 p->agent, tmp, loginchan, logintime, uniqueid);
1571 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1575 "Logintime: %ld\r\n",
1576 p->agent, tmp, loginchan, logintime);
1579 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
1580 set_agentbycallerid(p->logincallerid, NULL);
1581 p->loginchan[0] ='\0';
1582 p->logincallerid[0] = '\0';
1583 p->inherited_devicestate = -1;
1584 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
1585 if (persistent_agents)
1590 static int agent_logoff(const char *agent, int soft)
1592 struct agent_pvt *p;
1594 int ret = -1; /* Return -1 if no agent if found */
1596 AST_LIST_LOCK(&agents);
1597 AST_LIST_TRAVERSE(&agents, p, list) {
1598 if (!strcasecmp(p->agent, agent)) {
1600 if (p->owner || p->chan) {
1602 ast_mutex_lock(&p->lock);
1604 while (p->owner && ast_channel_trylock(p->owner)) {
1605 DEADLOCK_AVOIDANCE(&p->lock);
1608 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1609 ast_channel_unlock(p->owner);
1612 while (p->chan && ast_channel_trylock(p->chan)) {
1613 DEADLOCK_AVOIDANCE(&p->lock);
1616 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1617 ast_channel_unlock(p->chan);
1620 ast_mutex_unlock(&p->lock);
1624 logintime = time(NULL) - p->loginstart;
1626 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
1631 AST_LIST_UNLOCK(&agents);
1636 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1643 e->command = "agent logoff";
1645 "Usage: agent logoff <channel> [soft]\n"
1646 " Sets an agent as no longer logged in.\n"
1647 " If 'soft' is specified, do not hangup existing calls.\n";
1650 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n);
1653 if (a->argc < 3 || a->argc > 4)
1654 return CLI_SHOWUSAGE;
1655 if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
1656 return CLI_SHOWUSAGE;
1658 agent = a->argv[2] + 6;
1659 ret = agent_logoff(agent, a->argc == 4);
1661 ast_cli(a->fd, "Logging out %s\n", agent);
1667 * Sets an agent as no longer logged in in the Manager API.
1668 * It is registered on load_module() and it gets called by the manager backend.
1672 * \sa action_agents(), load_module().
1674 static int action_agent_logoff(struct mansession *s, const struct message *m)
1676 const char *agent = astman_get_header(m, "Agent");
1677 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1679 int ret; /* return value of agent_logoff */
1681 if (ast_strlen_zero(agent)) {
1682 astman_send_error(s, m, "No agent specified");
1686 soft = ast_true(soft_s) ? 1 : 0;
1687 ret = agent_logoff(agent, soft);
1689 astman_send_ack(s, m, "Agent logged out");
1691 astman_send_error(s, m, "No such agent");
1696 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1701 struct agent_pvt *p;
1702 char name[AST_MAX_AGENT];
1703 int which = 0, len = strlen(word);
1705 AST_LIST_LOCK(&agents);
1706 AST_LIST_TRAVERSE(&agents, p, list) {
1707 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1708 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
1709 ret = ast_strdup(name);
1713 AST_LIST_UNLOCK(&agents);
1714 } else if (pos == 3 && state == 0)
1715 return ast_strdup("soft");
1721 * Show agents in cli.
1723 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1725 struct agent_pvt *p;
1726 char username[AST_MAX_BUF];
1727 char location[AST_MAX_BUF] = "";
1728 char talkingto[AST_MAX_BUF] = "";
1729 char moh[AST_MAX_BUF];
1730 int count_agents = 0; /*!< Number of agents configured */
1731 int online_agents = 0; /*!< Number of online agents */
1732 int offline_agents = 0; /*!< Number of offline agents */
1736 e->command = "agent show";
1738 "Usage: agent show\n"
1739 " Provides summary information on agents.\n";
1746 return CLI_SHOWUSAGE;
1748 AST_LIST_LOCK(&agents);
1749 AST_LIST_TRAVERSE(&agents, p, list) {
1750 ast_mutex_lock(&p->lock);
1753 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
1755 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
1757 if (!ast_strlen_zero(p->name))
1758 snprintf(username, sizeof(username), "(%s) ", p->name);
1762 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1763 if (p->owner && ast_bridged_channel(p->owner))
1764 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1766 strcpy(talkingto, " is idle");
1768 } else if (!ast_strlen_zero(p->loginchan)) {
1769 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec))
1770 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1772 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
1773 talkingto[0] = '\0';
1775 if (p->acknowledged)
1776 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1778 strcpy(location, "not logged in");
1779 talkingto[0] = '\0';
1782 if (!ast_strlen_zero(p->moh))
1783 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1784 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent,
1785 username, location, talkingto, moh);
1788 ast_mutex_unlock(&p->lock);
1790 AST_LIST_UNLOCK(&agents);
1791 if ( !count_agents )
1792 ast_cli(a->fd, "No Agents are configured in %s\n",config);
1794 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1795 ast_cli(a->fd, "\n");
1801 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1803 struct agent_pvt *p;
1804 char username[AST_MAX_BUF];
1805 char location[AST_MAX_BUF] = "";
1806 char talkingto[AST_MAX_BUF] = "";
1807 char moh[AST_MAX_BUF];
1808 int count_agents = 0; /* Number of agents configured */
1809 int online_agents = 0; /* Number of online agents */
1810 int agent_status = 0; /* 0 means offline, 1 means online */
1814 e->command = "agent show online";
1816 "Usage: agent show online\n"
1817 " Provides a list of all online agents.\n";
1824 return CLI_SHOWUSAGE;
1826 AST_LIST_LOCK(&agents);
1827 AST_LIST_TRAVERSE(&agents, p, list) {
1828 agent_status = 0; /* reset it to offline */
1829 ast_mutex_lock(&p->lock);
1830 if (!ast_strlen_zero(p->name))
1831 snprintf(username, sizeof(username), "(%s) ", p->name);
1835 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1836 if (p->owner && ast_bridged_channel(p->owner))
1837 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1839 strcpy(talkingto, " is idle");
1842 } else if (!ast_strlen_zero(p->loginchan)) {
1843 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1844 talkingto[0] = '\0';
1847 if (p->acknowledged)
1848 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1850 if (!ast_strlen_zero(p->moh))
1851 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1853 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, moh);
1855 ast_mutex_unlock(&p->lock);
1857 AST_LIST_UNLOCK(&agents);
1859 ast_cli(a->fd, "No Agents are configured in %s\n", config);
1861 ast_cli(a->fd, "%d agents online\n", online_agents);
1862 ast_cli(a->fd, "\n");
1866 static const char agent_logoff_usage[] =
1867 "Usage: agent logoff <channel> [soft]\n"
1868 " Sets an agent as no longer logged in.\n"
1869 " If 'soft' is specified, do not hangup existing calls.\n";
1871 static struct ast_cli_entry cli_agents[] = {
1872 AST_CLI_DEFINE(agents_show, "Show status of agents"),
1873 AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
1874 AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
1878 * Called by the AgentLogin application (from the dial plan).
1880 * \brief Log in agent application.
1885 * \sa agentmonitoroutgoing_exec(), load_module().
1887 static int login_exec(struct ast_channel *chan, void *data)
1891 int max_login_tries = maxlogintries;
1892 struct agent_pvt *p;
1893 struct ast_module_user *u;
1894 int login_state = 0;
1895 char user[AST_MAX_AGENT] = "";
1896 char pass[AST_MAX_AGENT];
1897 char agent[AST_MAX_AGENT] = "";
1898 char xpass[AST_MAX_AGENT] = "";
1901 AST_DECLARE_APP_ARGS(args,
1902 AST_APP_ARG(agent_id);
1903 AST_APP_ARG(options);
1904 AST_APP_ARG(extension);
1906 const char *tmpoptions = NULL;
1907 int play_announcement = 1;
1908 char agent_goodbye[AST_MAX_FILENAME_LEN];
1909 int update_cdr = updatecdr;
1910 char *filename = "agent-loginok";
1912 u = ast_module_user_add(chan);
1914 parse = ast_strdupa(data);
1916 AST_STANDARD_APP_ARGS(args, parse);
1918 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1920 ast_channel_lock(chan);
1921 /* Set Channel Specific Login Overrides */
1922 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1923 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1924 if (max_login_tries < 0)
1925 max_login_tries = 0;
1926 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1927 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1929 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1930 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1934 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1935 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1937 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1938 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1939 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1940 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1942 ast_channel_unlock(chan);
1943 /* End Channel Specific Login Overrides */
1945 if (!ast_strlen_zero(args.options)) {
1946 if (strchr(args.options, 's')) {
1947 play_announcement = 0;
1951 if (chan->_state != AST_STATE_UP)
1952 res = ast_answer(chan);
1954 if (!ast_strlen_zero(args.agent_id))
1955 ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1957 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1959 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1961 /* Check for password */
1962 AST_LIST_LOCK(&agents);
1963 AST_LIST_TRAVERSE(&agents, p, list) {
1964 if (!strcmp(p->agent, user) && !p->pending)
1965 ast_copy_string(xpass, p->password, sizeof(xpass));
1967 AST_LIST_UNLOCK(&agents);
1969 if (!ast_strlen_zero(xpass))
1970 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1974 errmsg = "agent-incorrect";
1977 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1980 /* Check again for accuracy */
1981 AST_LIST_LOCK(&agents);
1982 AST_LIST_TRAVERSE(&agents, p, list) {
1983 int unlock_channel = 1;
1984 ast_channel_lock(chan);
1985 ast_mutex_lock(&p->lock);
1986 if (!strcmp(p->agent, user) &&
1987 !strcmp(p->password, pass) && !p->pending) {
1988 login_state = 1; /* Successful Login */
1990 /* Ensure we can't be gotten until we're done */
1991 p->lastdisc = ast_tvnow();
1992 p->lastdisc.tv_sec++;
1994 /* Set Channel Specific Agent Overrides */
1995 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1996 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1998 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
2002 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2003 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
2005 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
2006 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
2007 if (p->autologoff < 0)
2009 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2010 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
2012 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
2013 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
2014 if (p->wrapuptime < 0)
2016 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2017 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
2019 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDMTF");
2020 if (!ast_strlen_zero(tmpoptions)) {
2021 p->acceptdtmf = *tmpoptions;
2022 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
2024 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
2025 if (!ast_strlen_zero(tmpoptions)) {
2026 p->enddtmf = *tmpoptions;
2027 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
2029 ast_channel_unlock(chan);
2031 /* End Channel Specific Agent Overrides */
2034 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
2036 p->loginchan[0] = '\0';
2037 p->logincallerid[0] = '\0';
2038 p->acknowledged = 0;
2040 ast_mutex_unlock(&p->lock);
2041 AST_LIST_UNLOCK(&agents);
2042 if( !res && play_announcement==1 )
2043 res = ast_streamfile(chan, filename, chan->language);
2045 ast_waitstream(chan, "");
2046 AST_LIST_LOCK(&agents);
2047 ast_mutex_lock(&p->lock);
2049 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
2051 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
2054 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
2056 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
2058 /* Check once more just in case */
2062 ast_indicate_data(chan, AST_CONTROL_HOLD,
2064 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2065 if (p->loginstart == 0)
2066 time(&p->loginstart);
2067 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2071 p->agent, chan->name, chan->uniqueid);
2072 if (update_cdr && chan->cdr)
2073 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2074 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
2075 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
2076 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
2077 /* Login this channel and wait for it to go away */
2082 check_availability(p, 0);
2083 ast_mutex_unlock(&p->lock);
2084 AST_LIST_UNLOCK(&agents);
2085 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2087 ast_mutex_lock(&p->lock);
2088 if (p->deferlogoff && p->chan) {
2089 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
2092 if (p->chan != chan)
2094 ast_mutex_unlock(&p->lock);
2095 /* Yield here so other interested threads can kick in. */
2100 AST_LIST_LOCK(&agents);
2101 ast_mutex_lock(&p->lock);
2102 if (p->lastdisc.tv_sec) {
2103 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
2104 ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
2105 p->lastdisc = ast_tv(0, 0);
2106 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2110 check_availability(p, 0);
2113 ast_mutex_unlock(&p->lock);
2114 AST_LIST_UNLOCK(&agents);
2115 /* Synchronize channel ownership between call to agent and itself. */
2116 ast_mutex_lock( &p->app_lock );
2117 ast_mutex_lock(&p->lock);
2118 p->owning_app = pthread_self();
2119 ast_mutex_unlock(&p->lock);
2121 res = agent_ack_sleep(p);
2123 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2124 ast_mutex_unlock( &p->app_lock );
2125 if ((p->ackcall > 1) && (res == 1)) {
2126 AST_LIST_LOCK(&agents);
2127 ast_mutex_lock(&p->lock);
2128 check_availability(p, 0);
2129 ast_mutex_unlock(&p->lock);
2130 AST_LIST_UNLOCK(&agents);
2135 ast_mutex_lock(&p->lock);
2136 if (res && p->owner)
2137 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
2138 /* Log us off if appropriate */
2139 if (p->chan == chan) {
2141 p->inherited_devicestate = -1;
2143 p->acknowledged = 0;
2144 logintime = time(NULL) - p->loginstart;
2146 ast_mutex_unlock(&p->lock);
2147 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2149 "Logintime: %ld\r\n"
2151 p->agent, logintime, chan->uniqueid);
2152 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2153 ast_verb(2, "Agent '%s' logged out\n", p->agent);
2154 /* If there is no owner, go ahead and kill it now */
2155 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
2156 if (p->dead && !p->owner) {
2157 ast_mutex_destroy(&p->lock);
2158 ast_mutex_destroy(&p->app_lock);
2163 ast_mutex_unlock(&p->lock);
2168 ast_mutex_unlock(&p->lock);
2169 errmsg = "agent-alreadyon";
2174 ast_mutex_unlock(&p->lock);
2175 if (unlock_channel) {
2176 ast_channel_unlock(chan);
2180 AST_LIST_UNLOCK(&agents);
2182 if (!res && (max_login_tries==0 || tries < max_login_tries))
2183 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2187 res = ast_safe_sleep(chan, 500);
2189 ast_module_user_remove(u);
2195 * \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2200 * \sa login_exec(), load_module().
2202 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2204 int exitifnoagentid = 0;
2206 int changeoutgoing = 0;
2208 char agent[AST_MAX_AGENT];
2211 if (strchr(data, 'd'))
2212 exitifnoagentid = 1;
2213 if (strchr(data, 'n'))
2215 if (strchr(data, 'c'))
2218 if (chan->cid.cid_num) {
2220 char agentvar[AST_MAX_BUF];
2221 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2222 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2223 struct agent_pvt *p;
2224 ast_copy_string(agent, tmp, sizeof(agent));
2225 AST_LIST_LOCK(&agents);
2226 AST_LIST_TRAVERSE(&agents, p, list) {
2227 if (!strcasecmp(p->agent, tmp)) {
2228 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2229 __agent_start_monitoring(chan, p, 1);
2233 AST_LIST_UNLOCK(&agents);
2238 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);
2243 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");
2246 if (exitifnoagentid)
2253 * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
2255 static void dump_agents(void)
2257 struct agent_pvt *cur_agent = NULL;
2260 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2261 if (cur_agent->chan)
2264 if (!ast_strlen_zero(cur_agent->loginchan)) {
2265 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2266 if (ast_db_put(pa_family, cur_agent->agent, buf))
2267 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
2269 ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2271 /* Delete - no agent or there is an error */
2272 ast_db_del(pa_family, cur_agent->agent);
2278 * \brief Reload the persistent agents from astdb.
2280 static void reload_agents(void)
2283 struct ast_db_entry *db_tree;
2284 struct ast_db_entry *entry;
2285 struct agent_pvt *cur_agent;
2286 char agent_data[256];
2289 char *agent_callerid;
2291 db_tree = ast_db_gettree(pa_family, NULL);
2293 AST_LIST_LOCK(&agents);
2294 for (entry = db_tree; entry; entry = entry->next) {
2295 agent_num = entry->key + strlen(pa_family) + 2;
2296 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2297 ast_mutex_lock(&cur_agent->lock);
2298 if (strcmp(agent_num, cur_agent->agent) == 0)
2300 ast_mutex_unlock(&cur_agent->lock);
2303 ast_db_del(pa_family, agent_num);
2306 ast_mutex_unlock(&cur_agent->lock);
2307 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2308 ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
2310 agent_chan = strsep(&parse, ";");
2311 agent_callerid = strsep(&parse, ";");
2312 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2313 if (agent_callerid) {
2314 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2315 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2317 cur_agent->logincallerid[0] = '\0';
2318 if (cur_agent->loginstart == 0)
2319 time(&cur_agent->loginstart);
2320 ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent);
2323 AST_LIST_UNLOCK(&agents);
2325 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
2326 ast_db_freetree(db_tree);
2330 /*! \brief Part of PBX channel interface */
2331 static int agent_devicestate(void *data)
2333 struct agent_pvt *p;
2335 ast_group_t groupmatch;
2337 int res = AST_DEVICE_INVALID;
2340 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
2341 groupmatch = (1 << groupoff);
2342 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2343 groupmatch = (1 << groupoff);
2347 /* Check actual logged in agents first */
2348 AST_LIST_LOCK(&agents);
2349 AST_LIST_TRAVERSE(&agents, p, list) {
2350 ast_mutex_lock(&p->lock);
2351 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2353 if (res != AST_DEVICE_INUSE)
2354 res = AST_DEVICE_BUSY;
2355 } else if (p->inherited_devicestate > -1) {
2356 res = p->inherited_devicestate;
2358 if (res == AST_DEVICE_BUSY)
2359 res = AST_DEVICE_INUSE;
2360 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2361 if (res == AST_DEVICE_INVALID)
2362 res = AST_DEVICE_UNKNOWN;
2363 } else if (res == AST_DEVICE_INVALID)
2364 res = AST_DEVICE_UNAVAILABLE;
2366 if (!strcmp(data, p->agent)) {
2367 ast_mutex_unlock(&p->lock);
2371 ast_mutex_unlock(&p->lock);
2373 AST_LIST_UNLOCK(&agents);
2378 * \note This function expects the agent list to be locked
2380 static struct agent_pvt *find_agent(char *agentid)
2382 struct agent_pvt *cur;
2384 AST_LIST_TRAVERSE(&agents, cur, list) {
2385 if (!strcmp(cur->agent, agentid))
2392 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2395 AST_DECLARE_APP_ARGS(args,
2396 AST_APP_ARG(agentid);
2400 struct agent_pvt *agent;
2404 if (ast_strlen_zero(data)) {
2405 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2409 parse = ast_strdupa(data);
2411 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2413 args.item = "status";
2415 AST_LIST_LOCK(&agents);
2417 if (!(agent = find_agent(args.agentid))) {
2418 AST_LIST_UNLOCK(&agents);
2419 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2423 if (!strcasecmp(args.item, "status")) {
2424 char *status = "LOGGEDOUT";
2425 if (agent->chan || !ast_strlen_zero(agent->loginchan))
2426 status = "LOGGEDIN";
2427 ast_copy_string(buf, status, len);
2428 } else if (!strcasecmp(args.item, "password"))
2429 ast_copy_string(buf, agent->password, len);
2430 else if (!strcasecmp(args.item, "name"))
2431 ast_copy_string(buf, agent->name, len);
2432 else if (!strcasecmp(args.item, "mohclass"))
2433 ast_copy_string(buf, agent->moh, len);
2434 else if (!strcasecmp(args.item, "channel")) {
2436 ast_copy_string(buf, agent->chan->name, len);
2437 tmp = strrchr(buf, '-');
2441 } else if (!strcasecmp(args.item, "exten"))
2442 ast_copy_string(buf, agent->loginchan, len);
2444 AST_LIST_UNLOCK(&agents);
2449 struct ast_custom_function agent_function = {
2451 .synopsis = "Gets information about an Agent",
2452 .syntax = "AGENT(<agentid>[:item])",
2453 .read = function_agent,
2454 .desc = "The valid items to retrieve are:\n"
2455 "- status (default) The status of the agent\n"
2456 " LOGGEDIN | LOGGEDOUT\n"
2457 "- password The password of the agent\n"
2458 "- name The name of the agent\n"
2459 "- mohclass MusicOnHold class\n"
2460 "- exten The callback extension for the Agent (AgentCallbackLogin)\n"
2461 "- channel The name of the active channel for the Agent (AgentLogin)\n"
2466 * \brief Initialize the Agents module.
2467 * This function is being called by Asterisk when loading the module.
2468 * Among other things it registers applications, cli commands and reads the cofiguration file.
2470 * \returns int Always 0.
2472 static int load_module(void)
2474 /* Make sure we can register our agent channel type */
2475 if (ast_channel_register(&agent_tech)) {
2476 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2477 return AST_MODULE_LOAD_FAILURE;
2479 /* Read in the config */
2480 if (!read_agent_config(0))
2481 return AST_MODULE_LOAD_DECLINE;
2482 if (persistent_agents)
2484 /* Dialplan applications */
2485 ast_register_application(app, login_exec, synopsis, descrip);
2486 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2488 /* Manager commands */
2489 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2490 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2493 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2495 /* Dialplan Functions */
2496 ast_custom_function_register(&agent_function);
2498 agent_devicestate_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
2499 agent_devicestate_cb, NULL, AST_EVENT_IE_END);
2501 return AST_MODULE_LOAD_SUCCESS;
2504 static int reload(void)
2506 if (!read_agent_config(1)) {
2507 if (persistent_agents)
2513 static int unload_module(void)
2515 struct agent_pvt *p;
2516 /* First, take us out of the channel loop */
2517 ast_channel_unregister(&agent_tech);
2518 /* Delete devicestate subscription */
2519 agent_devicestate_sub = ast_event_unsubscribe(agent_devicestate_sub);
2520 /* Unregister dialplan functions */
2521 ast_custom_function_unregister(&agent_function);
2522 /* Unregister CLI commands */
2523 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2524 /* Unregister dialplan applications */
2525 ast_unregister_application(app);
2526 ast_unregister_application(app3);
2527 /* Unregister manager command */
2528 ast_manager_unregister("Agents");
2529 ast_manager_unregister("AgentLogoff");
2530 /* Unregister channel */
2531 AST_LIST_LOCK(&agents);
2532 /* Hangup all interfaces if they have an owner */
2533 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2535 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2538 AST_LIST_UNLOCK(&agents);
2542 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
2543 .load = load_module,
2544 .unload = unload_module,