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 base[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(base, p->chan->name, sizeof(base));
301 if ((tmp = strrchr(base, '-'))) {
304 if (strcasecmp(p->chan->name, device) == 0 || strcasecmp(base, 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);
658 if (p->chan && !ast_check_hangup(p->chan))
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 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1123 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config);
1126 if ((ucfg = ast_config_load("users.conf", config_flags))) {
1127 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
1129 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
1130 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n");
1135 AST_LIST_LOCK(&agents);
1136 AST_LIST_TRAVERSE(&agents, p, list) {
1139 strcpy(moh, "default");
1140 /* set the default recording values */
1141 recordagentcalls = 0;
1142 strcpy(recordformat, "wav");
1143 strcpy(recordformatext, "wav");
1144 urlprefix[0] = '\0';
1145 savecallsin[0] = '\0';
1147 /* Read in [general] section for persistence */
1148 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1149 persistent_agents = ast_true(general_val);
1150 multiplelogin = ast_true(ast_variable_retrieve(cfg, "general", "multiplelogin"));
1152 /* Read in the [agents] section */
1153 v = ast_variable_browse(cfg, "agents");
1155 /* Create the interface list */
1156 if (!strcasecmp(v->name, "agent")) {
1157 add_agent(v->value, 0);
1158 } else if (!strcasecmp(v->name, "group")) {
1159 group = ast_get_group(v->value);
1160 } else if (!strcasecmp(v->name, "autologoff")) {
1161 autologoff = atoi(v->value);
1164 } else if (!strcasecmp(v->name, "ackcall")) {
1165 if (!strcasecmp(v->value, "always"))
1167 else if (ast_true(v->value))
1171 } else if (!strcasecmp(v->name, "endcall")) {
1172 endcall = ast_true(v->value);
1173 } else if (!strcasecmp(v->name, "acceptdtmf")) {
1174 acceptdtmf = *(v->value);
1175 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
1176 } else if (!strcasecmp(v->name, "enddtmf")) {
1177 enddtmf = *(v->value);
1178 } else if (!strcasecmp(v->name, "wrapuptime")) {
1179 wrapuptime = atoi(v->value);
1182 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1183 maxlogintries = atoi(v->value);
1184 if (maxlogintries < 0)
1186 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1187 strcpy(agentgoodbye,v->value);
1188 } else if (!strcasecmp(v->name, "musiconhold")) {
1189 ast_copy_string(moh, v->value, sizeof(moh));
1190 } else if (!strcasecmp(v->name, "updatecdr")) {
1191 if (ast_true(v->value))
1195 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1196 if (ast_true(v->value))
1197 autologoffunavail = 1;
1199 autologoffunavail = 0;
1200 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1201 recordagentcalls = ast_true(v->value);
1202 } else if (!strcasecmp(v->name, "recordformat")) {
1203 ast_copy_string(recordformat, v->value, sizeof(recordformat));
1204 if (!strcasecmp(v->value, "wav49"))
1205 strcpy(recordformatext, "WAV");
1207 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1208 } else if (!strcasecmp(v->name, "urlprefix")) {
1209 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1210 if (urlprefix[strlen(urlprefix) - 1] != '/')
1211 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1212 } else if (!strcasecmp(v->name, "savecallsin")) {
1213 if (v->value[0] == '/')
1214 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1216 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1217 if (savecallsin[strlen(savecallsin) - 1] != '/')
1218 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1219 } else if (!strcasecmp(v->name, "custom_beep")) {
1220 ast_copy_string(beep, v->value, sizeof(beep));
1225 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1226 catname = ast_category_browse(ucfg, NULL);
1228 if (strcasecmp(catname, "general")) {
1229 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1230 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1232 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1233 const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1238 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1242 catname = ast_category_browse(ucfg, catname);
1244 ast_config_destroy(ucfg);
1246 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1248 AST_LIST_REMOVE_CURRENT(list);
1249 /* Destroy if appropriate */
1252 ast_mutex_destroy(&p->lock);
1253 ast_mutex_destroy(&p->app_lock);
1256 /* Cause them to hang up */
1257 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1262 AST_LIST_TRAVERSE_SAFE_END;
1263 AST_LIST_UNLOCK(&agents);
1264 ast_config_destroy(cfg);
1268 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1270 struct ast_channel *chan=NULL, *parent=NULL;
1271 struct agent_pvt *p;
1274 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
1276 AST_LIST_LOCK(&agents);
1277 AST_LIST_TRAVERSE(&agents, p, list) {
1278 if (p == newlyavailable) {
1281 ast_mutex_lock(&p->lock);
1282 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1283 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1284 /* We found a pending call, time to merge */
1285 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1288 ast_mutex_unlock(&p->lock);
1291 ast_mutex_unlock(&p->lock);
1294 AST_LIST_UNLOCK(&agents);
1295 if (parent && chan) {
1296 if (newlyavailable->ackcall > 1) {
1297 /* Don't do beep here */
1300 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1301 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1302 ast_debug(3, "Played beep, result '%d'\n", res);
1304 res = ast_waitstream(newlyavailable->chan, "");
1305 ast_debug(1, "Waited for stream, result '%d'\n", res);
1309 /* Note -- parent may have disappeared */
1310 if (p->abouttograb) {
1311 newlyavailable->acknowledged = 1;
1312 /* Safe -- agent lock already held */
1313 ast_setstate(parent, AST_STATE_UP);
1314 ast_setstate(chan, AST_STATE_UP);
1315 ast_copy_string(parent->context, chan->context, sizeof(parent->context));
1316 /* Go ahead and mark the channel as a zombie so that masquerade will
1317 destroy it for us, and we need not call ast_hangup */
1318 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1319 ast_channel_masquerade(parent, chan);
1322 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1323 agent_cleanup(newlyavailable);
1326 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n");
1327 agent_cleanup(newlyavailable);
1333 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1335 struct agent_pvt *p;
1338 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1340 AST_LIST_LOCK(&agents);
1341 AST_LIST_TRAVERSE(&agents, p, list) {
1342 if (p == newlyavailable) {
1345 ast_mutex_lock(&p->lock);
1346 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1347 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1348 ast_mutex_unlock(&p->lock);
1351 ast_mutex_unlock(&p->lock);
1354 AST_LIST_UNLOCK(&agents);
1356 ast_mutex_unlock(&newlyavailable->lock);
1357 ast_debug(3, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1358 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1359 ast_debug(1, "Played beep, result '%d'\n", res);
1361 res = ast_waitstream(newlyavailable->chan, "");
1362 ast_debug(1, "Waited for stream, result '%d'\n", res);
1364 ast_mutex_lock(&newlyavailable->lock);
1369 /*! \brief Part of the Asterisk PBX interface */
1370 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1372 struct agent_pvt *p;
1373 struct ast_channel *chan = NULL;
1375 ast_group_t groupmatch;
1382 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1383 groupmatch = (1 << groupoff);
1384 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1385 groupmatch = (1 << groupoff);
1390 /* Check actual logged in agents first */
1391 AST_LIST_LOCK(&agents);
1392 AST_LIST_TRAVERSE(&agents, p, list) {
1393 ast_mutex_lock(&p->lock);
1394 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1395 ast_strlen_zero(p->loginchan)) {
1399 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1400 p->lastdisc = ast_tv(0, 0);
1401 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1402 if (!p->owner && p->chan) {
1404 chan = agent_new(p, AST_STATE_DOWN);
1407 ast_mutex_unlock(&p->lock);
1412 ast_mutex_unlock(&p->lock);
1415 AST_LIST_TRAVERSE(&agents, p, list) {
1416 ast_mutex_lock(&p->lock);
1417 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1418 if (p->chan || !ast_strlen_zero(p->loginchan))
1422 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", now.tv_sec, p->lastdisc.tv_sec);
1424 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1425 p->lastdisc = ast_tv(0, 0);
1426 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1427 if (!p->owner && p->chan) {
1428 /* Could still get a fixed agent */
1429 chan = agent_new(p, AST_STATE_DOWN);
1430 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1431 /* Adjustable agent */
1432 p->chan = ast_request("Local", format, p->loginchan, cause);
1434 chan = agent_new(p, AST_STATE_DOWN);
1437 ast_mutex_unlock(&p->lock);
1442 ast_mutex_unlock(&p->lock);
1446 if (!chan && waitforagent) {
1447 /* No agent available -- but we're requesting to wait for one.
1448 Allocate a place holder */
1450 ast_debug(1, "Creating place holder for '%s'\n", s);
1451 p = add_agent(data, 1);
1452 p->group = groupmatch;
1453 chan = agent_new(p, AST_STATE_DOWN);
1455 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1457 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1460 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1461 AST_LIST_UNLOCK(&agents);
1465 static force_inline int powerof(unsigned int d)
1476 * Lists agents and their status to the Manager API.
1477 * It is registered on load_module() and it gets called by the manager backend.
1481 * \sa action_agent_logoff(), load_module().
1483 static int action_agents(struct mansession *s, const struct message *m)
1485 const char *id = astman_get_header(m,"ActionID");
1486 char idText[256] = "";
1488 struct agent_pvt *p;
1489 char *username = NULL;
1490 char *loginChan = NULL;
1491 char *talkingto = NULL;
1492 char *talkingtoChan = NULL;
1493 char *status = NULL;
1495 if (!ast_strlen_zero(id))
1496 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1497 astman_send_ack(s, m, "Agents will follow");
1498 AST_LIST_LOCK(&agents);
1499 AST_LIST_TRAVERSE(&agents, p, list) {
1500 ast_mutex_lock(&p->lock);
1503 AGENT_LOGGEDOFF - Agent isn't logged in
1504 AGENT_IDLE - Agent is logged in, and waiting for call
1505 AGENT_ONCALL - Agent is logged in, and on a call
1506 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1508 username = S_OR(p->name, "None");
1510 /* Set a default status. It 'should' get changed. */
1511 status = "AGENT_UNKNOWN";
1513 if (!ast_strlen_zero(p->loginchan) && !p->chan) {
1514 loginChan = p->loginchan;
1516 talkingtoChan = "n/a";
1517 status = "AGENT_IDLE";
1518 if (p->acknowledged) {
1519 snprintf(chanbuf, sizeof(chanbuf), " %s (Confirmed)", p->loginchan);
1520 loginChan = chanbuf;
1522 } else if (p->chan) {
1523 loginChan = ast_strdupa(p->chan->name);
1524 if (p->owner && p->owner->_bridge) {
1525 talkingto = p->chan->cid.cid_num;
1526 if (ast_bridged_channel(p->owner))
1527 talkingtoChan = ast_strdupa(ast_bridged_channel(p->owner)->name);
1529 talkingtoChan = "n/a";
1530 status = "AGENT_ONCALL";
1533 talkingtoChan = "n/a";
1534 status = "AGENT_IDLE";
1539 talkingtoChan = "n/a";
1540 status = "AGENT_LOGGEDOFF";
1543 astman_append(s, "Event: Agents\r\n"
1547 "LoggedInChan: %s\r\n"
1548 "LoggedInTime: %d\r\n"
1550 "TalkingToChan: %s\r\n"
1553 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1554 ast_mutex_unlock(&p->lock);
1556 AST_LIST_UNLOCK(&agents);
1557 astman_append(s, "Event: AgentsComplete\r\n"
1563 static void agent_logoff_maintenance(struct agent_pvt *p, char *loginchan, long logintime, const char *uniqueid, char *logcommand)
1566 char agent[AST_MAX_AGENT];
1568 if (!ast_strlen_zero(logcommand))
1571 tmp = ast_strdupa("");
1573 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1575 if (!ast_strlen_zero(uniqueid)) {
1576 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1580 "Logintime: %ld\r\n"
1582 p->agent, tmp, loginchan, logintime, uniqueid);
1584 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1588 "Logintime: %ld\r\n",
1589 p->agent, tmp, loginchan, logintime);
1592 ast_queue_log("NONE", ast_strlen_zero(uniqueid) ? "NONE" : uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", loginchan, logintime, tmp);
1593 set_agentbycallerid(p->logincallerid, NULL);
1594 p->loginchan[0] ='\0';
1595 p->logincallerid[0] = '\0';
1596 p->inherited_devicestate = -1;
1597 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
1598 if (persistent_agents)
1603 static int agent_logoff(const char *agent, int soft)
1605 struct agent_pvt *p;
1607 int ret = -1; /* Return -1 if no agent if found */
1609 AST_LIST_LOCK(&agents);
1610 AST_LIST_TRAVERSE(&agents, p, list) {
1611 if (!strcasecmp(p->agent, agent)) {
1613 if (p->owner || p->chan) {
1615 ast_mutex_lock(&p->lock);
1617 while (p->owner && ast_channel_trylock(p->owner)) {
1618 DEADLOCK_AVOIDANCE(&p->lock);
1621 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1622 ast_channel_unlock(p->owner);
1625 while (p->chan && ast_channel_trylock(p->chan)) {
1626 DEADLOCK_AVOIDANCE(&p->lock);
1629 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1630 ast_channel_unlock(p->chan);
1633 ast_mutex_unlock(&p->lock);
1637 logintime = time(NULL) - p->loginstart;
1639 agent_logoff_maintenance(p, p->loginchan, logintime, NULL, "CommandLogoff");
1644 AST_LIST_UNLOCK(&agents);
1649 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1656 e->command = "agent logoff";
1658 "Usage: agent logoff <channel> [soft]\n"
1659 " Sets an agent as no longer logged in.\n"
1660 " If 'soft' is specified, do not hangup existing calls.\n";
1663 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n);
1666 if (a->argc < 3 || a->argc > 4)
1667 return CLI_SHOWUSAGE;
1668 if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
1669 return CLI_SHOWUSAGE;
1671 agent = a->argv[2] + 6;
1672 ret = agent_logoff(agent, a->argc == 4);
1674 ast_cli(a->fd, "Logging out %s\n", agent);
1680 * Sets an agent as no longer logged in in the Manager API.
1681 * It is registered on load_module() and it gets called by the manager backend.
1685 * \sa action_agents(), load_module().
1687 static int action_agent_logoff(struct mansession *s, const struct message *m)
1689 const char *agent = astman_get_header(m, "Agent");
1690 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1692 int ret; /* return value of agent_logoff */
1694 if (ast_strlen_zero(agent)) {
1695 astman_send_error(s, m, "No agent specified");
1699 soft = ast_true(soft_s) ? 1 : 0;
1700 ret = agent_logoff(agent, soft);
1702 astman_send_ack(s, m, "Agent logged out");
1704 astman_send_error(s, m, "No such agent");
1709 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1714 struct agent_pvt *p;
1715 char name[AST_MAX_AGENT];
1716 int which = 0, len = strlen(word);
1718 AST_LIST_LOCK(&agents);
1719 AST_LIST_TRAVERSE(&agents, p, list) {
1720 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1721 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
1722 ret = ast_strdup(name);
1726 AST_LIST_UNLOCK(&agents);
1727 } else if (pos == 3 && state == 0)
1728 return ast_strdup("soft");
1734 * Show agents in cli.
1736 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1738 struct agent_pvt *p;
1739 char username[AST_MAX_BUF];
1740 char location[AST_MAX_BUF] = "";
1741 char talkingto[AST_MAX_BUF] = "";
1742 char music[AST_MAX_BUF];
1743 int count_agents = 0; /*!< Number of agents configured */
1744 int online_agents = 0; /*!< Number of online agents */
1745 int offline_agents = 0; /*!< Number of offline agents */
1749 e->command = "agent show";
1751 "Usage: agent show\n"
1752 " Provides summary information on agents.\n";
1759 return CLI_SHOWUSAGE;
1761 AST_LIST_LOCK(&agents);
1762 AST_LIST_TRAVERSE(&agents, p, list) {
1763 ast_mutex_lock(&p->lock);
1766 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
1768 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
1770 if (!ast_strlen_zero(p->name))
1771 snprintf(username, sizeof(username), "(%s) ", p->name);
1775 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1776 if (p->owner && ast_bridged_channel(p->owner))
1777 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1779 strcpy(talkingto, " is idle");
1781 } else if (!ast_strlen_zero(p->loginchan)) {
1782 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0 || !(p->lastdisc.tv_sec))
1783 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1785 snprintf(location, sizeof(location) - 20, "wrapping up at '%s'", p->loginchan);
1786 talkingto[0] = '\0';
1788 if (p->acknowledged)
1789 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1791 strcpy(location, "not logged in");
1792 talkingto[0] = '\0';
1795 if (!ast_strlen_zero(p->moh))
1796 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1797 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent,
1798 username, location, talkingto, music);
1801 ast_mutex_unlock(&p->lock);
1803 AST_LIST_UNLOCK(&agents);
1804 if ( !count_agents )
1805 ast_cli(a->fd, "No Agents are configured in %s\n",config);
1807 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1808 ast_cli(a->fd, "\n");
1814 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1816 struct agent_pvt *p;
1817 char username[AST_MAX_BUF];
1818 char location[AST_MAX_BUF] = "";
1819 char talkingto[AST_MAX_BUF] = "";
1820 char music[AST_MAX_BUF];
1821 int count_agents = 0; /* Number of agents configured */
1822 int online_agents = 0; /* Number of online agents */
1823 int agent_status = 0; /* 0 means offline, 1 means online */
1827 e->command = "agent show online";
1829 "Usage: agent show online\n"
1830 " Provides a list of all online agents.\n";
1837 return CLI_SHOWUSAGE;
1839 AST_LIST_LOCK(&agents);
1840 AST_LIST_TRAVERSE(&agents, p, list) {
1841 agent_status = 0; /* reset it to offline */
1842 ast_mutex_lock(&p->lock);
1843 if (!ast_strlen_zero(p->name))
1844 snprintf(username, sizeof(username), "(%s) ", p->name);
1848 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1849 if (p->owner && ast_bridged_channel(p->owner))
1850 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1852 strcpy(talkingto, " is idle");
1855 } else if (!ast_strlen_zero(p->loginchan)) {
1856 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1857 talkingto[0] = '\0';
1860 if (p->acknowledged)
1861 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1863 if (!ast_strlen_zero(p->moh))
1864 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1866 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
1868 ast_mutex_unlock(&p->lock);
1870 AST_LIST_UNLOCK(&agents);
1872 ast_cli(a->fd, "No Agents are configured in %s\n", config);
1874 ast_cli(a->fd, "%d agents online\n", online_agents);
1875 ast_cli(a->fd, "\n");
1879 static const char agent_logoff_usage[] =
1880 "Usage: agent logoff <channel> [soft]\n"
1881 " Sets an agent as no longer logged in.\n"
1882 " If 'soft' is specified, do not hangup existing calls.\n";
1884 static struct ast_cli_entry cli_agents[] = {
1885 AST_CLI_DEFINE(agents_show, "Show status of agents"),
1886 AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
1887 AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
1891 * Called by the AgentLogin application (from the dial plan).
1893 * \brief Log in agent application.
1898 * \sa agentmonitoroutgoing_exec(), load_module().
1900 static int login_exec(struct ast_channel *chan, void *data)
1904 int max_login_tries = maxlogintries;
1905 struct agent_pvt *p;
1906 struct ast_module_user *u;
1907 int login_state = 0;
1908 char user[AST_MAX_AGENT] = "";
1909 char pass[AST_MAX_AGENT];
1910 char agent[AST_MAX_AGENT] = "";
1911 char xpass[AST_MAX_AGENT] = "";
1914 AST_DECLARE_APP_ARGS(args,
1915 AST_APP_ARG(agent_id);
1916 AST_APP_ARG(options);
1917 AST_APP_ARG(extension);
1919 const char *tmpoptions = NULL;
1920 int play_announcement = 1;
1921 char agent_goodbye[AST_MAX_FILENAME_LEN];
1922 int update_cdr = updatecdr;
1923 char *filename = "agent-loginok";
1925 u = ast_module_user_add(chan);
1927 parse = ast_strdupa(data);
1929 AST_STANDARD_APP_ARGS(args, parse);
1931 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1933 ast_channel_lock(chan);
1934 /* Set Channel Specific Login Overrides */
1935 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1936 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1937 if (max_login_tries < 0)
1938 max_login_tries = 0;
1939 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1940 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1942 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1943 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1947 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1948 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1950 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1951 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1952 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1953 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1955 ast_channel_unlock(chan);
1956 /* End Channel Specific Login Overrides */
1958 if (!ast_strlen_zero(args.options)) {
1959 if (strchr(args.options, 's')) {
1960 play_announcement = 0;
1964 if (chan->_state != AST_STATE_UP)
1965 res = ast_answer(chan);
1967 if (!ast_strlen_zero(args.agent_id))
1968 ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1970 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1972 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1974 /* Check for password */
1975 AST_LIST_LOCK(&agents);
1976 AST_LIST_TRAVERSE(&agents, p, list) {
1977 if (!strcmp(p->agent, user) && !p->pending)
1978 ast_copy_string(xpass, p->password, sizeof(xpass));
1980 AST_LIST_UNLOCK(&agents);
1982 if (!ast_strlen_zero(xpass))
1983 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1987 errmsg = "agent-incorrect";
1990 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1993 /* Check again for accuracy */
1994 AST_LIST_LOCK(&agents);
1995 AST_LIST_TRAVERSE(&agents, p, list) {
1996 int unlock_channel = 1;
1997 ast_channel_lock(chan);
1998 ast_mutex_lock(&p->lock);
1999 if (!strcmp(p->agent, user) &&
2000 !strcmp(p->password, pass) && !p->pending) {
2001 login_state = 1; /* Successful Login */
2003 /* Ensure we can't be gotten until we're done */
2004 p->lastdisc = ast_tvnow();
2005 p->lastdisc.tv_sec++;
2007 /* Set Channel Specific Agent Overrides */
2008 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2009 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
2011 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
2015 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2016 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
2018 p->ackcall = ackcall;
2020 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
2021 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
2022 if (p->autologoff < 0)
2024 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2025 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
2027 p->autologoff = autologoff;
2029 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
2030 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
2031 if (p->wrapuptime < 0)
2033 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2034 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
2036 p->wrapuptime = wrapuptime;
2038 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDMTF");
2039 if (!ast_strlen_zero(tmpoptions)) {
2040 p->acceptdtmf = *tmpoptions;
2041 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
2043 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
2044 if (!ast_strlen_zero(tmpoptions)) {
2045 p->enddtmf = *tmpoptions;
2046 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
2048 ast_channel_unlock(chan);
2050 /* End Channel Specific Agent Overrides */
2053 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
2055 p->loginchan[0] = '\0';
2056 p->logincallerid[0] = '\0';
2057 p->acknowledged = 0;
2059 ast_mutex_unlock(&p->lock);
2060 AST_LIST_UNLOCK(&agents);
2061 if( !res && play_announcement==1 )
2062 res = ast_streamfile(chan, filename, chan->language);
2064 ast_waitstream(chan, "");
2065 AST_LIST_LOCK(&agents);
2066 ast_mutex_lock(&p->lock);
2068 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
2070 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
2073 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
2075 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
2077 /* Check once more just in case */
2081 ast_indicate_data(chan, AST_CONTROL_HOLD,
2083 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2084 if (p->loginstart == 0)
2085 time(&p->loginstart);
2086 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2090 p->agent, chan->name, chan->uniqueid);
2091 if (update_cdr && chan->cdr)
2092 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2093 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
2094 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
2095 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
2096 /* Login this channel and wait for it to go away */
2101 check_availability(p, 0);
2102 ast_mutex_unlock(&p->lock);
2103 AST_LIST_UNLOCK(&agents);
2104 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2106 ast_mutex_lock(&p->lock);
2107 if (p->deferlogoff && p->chan) {
2108 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
2111 if (p->chan != chan)
2113 ast_mutex_unlock(&p->lock);
2114 /* Yield here so other interested threads can kick in. */
2119 AST_LIST_LOCK(&agents);
2120 ast_mutex_lock(&p->lock);
2121 if (p->lastdisc.tv_sec) {
2122 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
2123 ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
2124 p->lastdisc = ast_tv(0, 0);
2125 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2129 check_availability(p, 0);
2132 ast_mutex_unlock(&p->lock);
2133 AST_LIST_UNLOCK(&agents);
2134 /* Synchronize channel ownership between call to agent and itself. */
2135 ast_mutex_lock( &p->app_lock );
2136 ast_mutex_lock(&p->lock);
2137 p->owning_app = pthread_self();
2138 ast_mutex_unlock(&p->lock);
2140 res = agent_ack_sleep(p);
2142 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2143 ast_mutex_unlock( &p->app_lock );
2144 if ((p->ackcall > 1) && (res == 1)) {
2145 AST_LIST_LOCK(&agents);
2146 ast_mutex_lock(&p->lock);
2147 check_availability(p, 0);
2148 ast_mutex_unlock(&p->lock);
2149 AST_LIST_UNLOCK(&agents);
2154 ast_mutex_lock(&p->lock);
2155 if (res && p->owner)
2156 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
2157 /* Log us off if appropriate */
2158 if (p->chan == chan) {
2160 p->inherited_devicestate = -1;
2162 p->acknowledged = 0;
2163 logintime = time(NULL) - p->loginstart;
2165 ast_mutex_unlock(&p->lock);
2166 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2168 "Logintime: %ld\r\n"
2170 p->agent, logintime, chan->uniqueid);
2171 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
2172 ast_verb(2, "Agent '%s' logged out\n", p->agent);
2173 /* If there is no owner, go ahead and kill it now */
2174 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
2175 if (p->dead && !p->owner) {
2176 ast_mutex_destroy(&p->lock);
2177 ast_mutex_destroy(&p->app_lock);
2182 ast_mutex_unlock(&p->lock);
2187 ast_mutex_unlock(&p->lock);
2188 errmsg = "agent-alreadyon";
2193 ast_mutex_unlock(&p->lock);
2194 if (unlock_channel) {
2195 ast_channel_unlock(chan);
2199 AST_LIST_UNLOCK(&agents);
2201 if (!res && (max_login_tries==0 || tries < max_login_tries))
2202 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2206 res = ast_safe_sleep(chan, 500);
2208 ast_module_user_remove(u);
2214 * \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2219 * \sa login_exec(), load_module().
2221 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2223 int exitifnoagentid = 0;
2225 int changeoutgoing = 0;
2227 char agent[AST_MAX_AGENT];
2230 if (strchr(data, 'd'))
2231 exitifnoagentid = 1;
2232 if (strchr(data, 'n'))
2234 if (strchr(data, 'c'))
2237 if (chan->cid.cid_num) {
2239 char agentvar[AST_MAX_BUF];
2240 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2241 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2242 struct agent_pvt *p;
2243 ast_copy_string(agent, tmp, sizeof(agent));
2244 AST_LIST_LOCK(&agents);
2245 AST_LIST_TRAVERSE(&agents, p, list) {
2246 if (!strcasecmp(p->agent, tmp)) {
2247 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2248 __agent_start_monitoring(chan, p, 1);
2252 AST_LIST_UNLOCK(&agents);
2257 ast_log(LOG_WARNING, "Couldn't find the global variable %s, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n", agentvar);
2262 ast_log(LOG_WARNING, "There is no callerid on that call, so I can't figure out which agent (if it's an agent) is placing outgoing call.\n");
2265 if (exitifnoagentid)
2272 * \brief Dump AgentCallbackLogin agents to the ASTdb database for persistence
2274 static void dump_agents(void)
2276 struct agent_pvt *cur_agent = NULL;
2279 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2280 if (cur_agent->chan)
2283 if (!ast_strlen_zero(cur_agent->loginchan)) {
2284 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2285 if (ast_db_put(pa_family, cur_agent->agent, buf))
2286 ast_log(LOG_WARNING, "failed to create persistent entry in ASTdb for %s!\n", buf);
2288 ast_debug(1, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2290 /* Delete - no agent or there is an error */
2291 ast_db_del(pa_family, cur_agent->agent);
2297 * \brief Reload the persistent agents from astdb.
2299 static void reload_agents(void)
2302 struct ast_db_entry *db_tree;
2303 struct ast_db_entry *entry;
2304 struct agent_pvt *cur_agent;
2305 char agent_data[256];
2308 char *agent_callerid;
2310 db_tree = ast_db_gettree(pa_family, NULL);
2312 AST_LIST_LOCK(&agents);
2313 for (entry = db_tree; entry; entry = entry->next) {
2314 agent_num = entry->key + strlen(pa_family) + 2;
2315 AST_LIST_TRAVERSE(&agents, cur_agent, list) {
2316 ast_mutex_lock(&cur_agent->lock);
2317 if (strcmp(agent_num, cur_agent->agent) == 0)
2319 ast_mutex_unlock(&cur_agent->lock);
2322 ast_db_del(pa_family, agent_num);
2325 ast_mutex_unlock(&cur_agent->lock);
2326 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2327 ast_debug(1, "Reload Agent from AstDB: %s on %s\n", cur_agent->agent, agent_data);
2329 agent_chan = strsep(&parse, ";");
2330 agent_callerid = strsep(&parse, ";");
2331 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2332 if (agent_callerid) {
2333 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2334 set_agentbycallerid(cur_agent->logincallerid, cur_agent->agent);
2336 cur_agent->logincallerid[0] = '\0';
2337 if (cur_agent->loginstart == 0)
2338 time(&cur_agent->loginstart);
2339 ast_devstate_changed(AST_DEVICE_UNKNOWN, "Agent/%s", cur_agent->agent);
2342 AST_LIST_UNLOCK(&agents);
2344 ast_log(LOG_NOTICE, "Agents successfully reloaded from database.\n");
2345 ast_db_freetree(db_tree);
2349 /*! \brief Part of PBX channel interface */
2350 static int agent_devicestate(void *data)
2352 struct agent_pvt *p;
2354 ast_group_t groupmatch;
2356 int res = AST_DEVICE_INVALID;
2359 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1))
2360 groupmatch = (1 << groupoff);
2361 else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2362 groupmatch = (1 << groupoff);
2366 /* Check actual logged in agents first */
2367 AST_LIST_LOCK(&agents);
2368 AST_LIST_TRAVERSE(&agents, p, list) {
2369 ast_mutex_lock(&p->lock);
2370 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2372 if (res != AST_DEVICE_INUSE)
2373 res = AST_DEVICE_BUSY;
2374 } else if (p->inherited_devicestate > -1) {
2375 res = p->inherited_devicestate;
2377 if (res == AST_DEVICE_BUSY)
2378 res = AST_DEVICE_INUSE;
2379 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2380 if (res == AST_DEVICE_INVALID)
2381 res = AST_DEVICE_UNKNOWN;
2382 } else if (res == AST_DEVICE_INVALID)
2383 res = AST_DEVICE_UNAVAILABLE;
2385 if (!strcmp(data, p->agent)) {
2386 ast_mutex_unlock(&p->lock);
2390 ast_mutex_unlock(&p->lock);
2392 AST_LIST_UNLOCK(&agents);
2397 * \note This function expects the agent list to be locked
2399 static struct agent_pvt *find_agent(char *agentid)
2401 struct agent_pvt *cur;
2403 AST_LIST_TRAVERSE(&agents, cur, list) {
2404 if (!strcmp(cur->agent, agentid))
2411 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2414 AST_DECLARE_APP_ARGS(args,
2415 AST_APP_ARG(agentid);
2419 struct agent_pvt *agent;
2423 if (ast_strlen_zero(data)) {
2424 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2428 parse = ast_strdupa(data);
2430 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2432 args.item = "status";
2434 AST_LIST_LOCK(&agents);
2436 if (!(agent = find_agent(args.agentid))) {
2437 AST_LIST_UNLOCK(&agents);
2438 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2442 if (!strcasecmp(args.item, "status")) {
2443 char *status = "LOGGEDOUT";
2444 if (agent->chan || !ast_strlen_zero(agent->loginchan))
2445 status = "LOGGEDIN";
2446 ast_copy_string(buf, status, len);
2447 } else if (!strcasecmp(args.item, "password"))
2448 ast_copy_string(buf, agent->password, len);
2449 else if (!strcasecmp(args.item, "name"))
2450 ast_copy_string(buf, agent->name, len);
2451 else if (!strcasecmp(args.item, "mohclass"))
2452 ast_copy_string(buf, agent->moh, len);
2453 else if (!strcasecmp(args.item, "channel")) {
2455 ast_copy_string(buf, agent->chan->name, len);
2456 tmp = strrchr(buf, '-');
2460 } else if (!strcasecmp(args.item, "exten"))
2461 ast_copy_string(buf, agent->loginchan, len);
2463 AST_LIST_UNLOCK(&agents);
2468 struct ast_custom_function agent_function = {
2470 .synopsis = "Gets information about an Agent",
2471 .syntax = "AGENT(<agentid>[:item])",
2472 .read = function_agent,
2473 .desc = "The valid items to retrieve are:\n"
2474 "- status (default) The status of the agent\n"
2475 " LOGGEDIN | LOGGEDOUT\n"
2476 "- password The password of the agent\n"
2477 "- name The name of the agent\n"
2478 "- mohclass MusicOnHold class\n"
2479 "- exten The callback extension for the Agent (AgentCallbackLogin)\n"
2480 "- channel The name of the active channel for the Agent (AgentLogin)\n"
2485 * \brief Initialize the Agents module.
2486 * This function is being called by Asterisk when loading the module.
2487 * Among other things it registers applications, cli commands and reads the cofiguration file.
2489 * \returns int Always 0.
2491 static int load_module(void)
2493 /* Make sure we can register our agent channel type */
2494 if (ast_channel_register(&agent_tech)) {
2495 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2496 return AST_MODULE_LOAD_FAILURE;
2498 /* Read in the config */
2499 if (!read_agent_config(0))
2500 return AST_MODULE_LOAD_DECLINE;
2501 if (persistent_agents)
2503 /* Dialplan applications */
2504 ast_register_application(app, login_exec, synopsis, descrip);
2505 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2507 /* Manager commands */
2508 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2509 ast_manager_register2("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff, "Sets an agent as no longer logged in", mandescr_agent_logoff);
2512 ast_cli_register_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2514 /* Dialplan Functions */
2515 ast_custom_function_register(&agent_function);
2517 agent_devicestate_sub = ast_event_subscribe(AST_EVENT_DEVICE_STATE,
2518 agent_devicestate_cb, NULL, AST_EVENT_IE_END);
2520 return AST_MODULE_LOAD_SUCCESS;
2523 static int reload(void)
2525 if (!read_agent_config(1)) {
2526 if (persistent_agents)
2532 static int unload_module(void)
2534 struct agent_pvt *p;
2535 /* First, take us out of the channel loop */
2536 ast_channel_unregister(&agent_tech);
2537 /* Delete devicestate subscription */
2538 if (agent_devicestate_sub) {
2539 agent_devicestate_sub = ast_event_unsubscribe(agent_devicestate_sub);
2541 /* Unregister dialplan functions */
2542 ast_custom_function_unregister(&agent_function);
2543 /* Unregister CLI commands */
2544 ast_cli_unregister_multiple(cli_agents, sizeof(cli_agents) / sizeof(struct ast_cli_entry));
2545 /* Unregister dialplan applications */
2546 ast_unregister_application(app);
2547 ast_unregister_application(app3);
2548 /* Unregister manager command */
2549 ast_manager_unregister("Agents");
2550 ast_manager_unregister("AgentLogoff");
2551 /* Unregister channel */
2552 AST_LIST_LOCK(&agents);
2553 /* Hangup all interfaces if they have an owner */
2554 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2556 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2559 AST_LIST_UNLOCK(&agents);
2563 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Agent Proxy Channel",
2564 .load = load_module,
2565 .unload = unload_module,