2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2012, 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>
35 <depend>res_monitor</depend>
36 <support_level>core</support_level>
41 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43 #include <sys/socket.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <sys/signal.h>
50 #include "asterisk/lock.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/config.h"
53 #include "asterisk/module.h"
54 #include "asterisk/pbx.h"
55 #include "asterisk/sched.h"
56 #include "asterisk/io.h"
57 #include "asterisk/acl.h"
58 #include "asterisk/callerid.h"
59 #include "asterisk/file.h"
60 #include "asterisk/cli.h"
61 #include "asterisk/app.h"
62 #include "asterisk/musiconhold.h"
63 #include "asterisk/manager.h"
64 #include "asterisk/features.h"
65 #include "asterisk/utils.h"
66 #include "asterisk/causes.h"
67 #include "asterisk/astdb.h"
68 #include "asterisk/devicestate.h"
69 #include "asterisk/monitor.h"
70 #include "asterisk/stringfields.h"
71 #include "asterisk/event.h"
72 #include "asterisk/data.h"
75 <application name="AgentLogin" language="en_US">
80 <parameter name="AgentNo" />
81 <parameter name="options">
84 <para>silent login - do not announce the login ok segment after
85 agent logged on/off</para>
91 <para>Asks the agent to login to the system. Always returns <literal>-1</literal>.
92 While logged in, the agent can receive calls and will hear a <literal>beep</literal>
93 when a new call comes in. The agent can dump the call by pressing the star key.</para>
96 <ref type="application">Queue</ref>
97 <ref type="application">AddQueueMember</ref>
98 <ref type="application">RemoveQueueMember</ref>
99 <ref type="application">PauseQueueMember</ref>
100 <ref type="application">UnpauseQueueMember</ref>
101 <ref type="function">AGENT</ref>
102 <ref type="filename">agents.conf</ref>
103 <ref type="filename">queues.conf</ref>
106 <application name="AgentMonitorOutgoing" language="en_US">
108 Record agent's outgoing call.
111 <parameter name="options">
114 <para>make the app return <literal>-1</literal> if there is an error condition.</para>
117 <para>change the CDR so that the source of the call is
118 <literal>Agent/agent_id</literal></para>
121 <para>don't generate the warnings when there is no callerid or the
122 agentid is not known. It's handy if you want to have one context
123 for agent and non-agent calls.</para>
129 <para>Tries to figure out the id of the agent who is placing outgoing call based on
130 comparison of the callerid of the current interface and the global variable
131 placed by the AgentCallbackLogin application. That's why it should be used only
132 with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent
133 instead of Monitor application. That has to be configured in the
134 <filename>agents.conf</filename> file.</para>
135 <para>Normally the app returns <literal>0</literal> unless the options are passed.</para>
138 <ref type="filename">agents.conf</ref>
141 <function name="AGENT" language="en_US">
143 Gets information about an Agent
146 <parameter name="agentid" required="true" />
147 <parameter name="item">
148 <para>The valid items to retrieve are:</para>
151 <para>(default) The status of the agent (LOGGEDIN | LOGGEDOUT)</para>
153 <enum name="password">
154 <para>The password of the agent</para>
157 <para>The name of the agent</para>
159 <enum name="mohclass">
160 <para>MusicOnHold class</para>
162 <enum name="channel">
163 <para>The name of the active channel for the Agent (AgentLogin)</para>
165 <enum name="fullchannel">
166 <para>The untruncated name of the active channel for the Agent (AgentLogin)</para>
171 <description></description>
173 <manager name="Agents" language="en_US">
175 Lists agents and their status.
178 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
181 <para>Will list info about all possible agents.</para>
184 <manager name="AgentLogoff" language="en_US">
186 Sets an agent as no longer logged in.
189 <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
190 <parameter name="Agent" required="true">
191 <para>Agent ID of the agent to log off.</para>
193 <parameter name="Soft">
194 <para>Set to <literal>true</literal> to not hangup existing calls.</para>
198 <para>Sets an agent as no longer logged in.</para>
203 static const char tdesc[] = "Call Agent Proxy Channel";
204 static const char config[] = "agents.conf";
206 static const char app[] = "AgentLogin";
207 static const char app3[] = "AgentMonitorOutgoing";
209 static char moh[80] = "default";
211 #define AST_MAX_AGENT 80 /*!< Agent ID or Password max length */
212 #define AST_MAX_BUF 256
213 #define AST_MAX_FILENAME_LEN 256
215 static const char pa_family[] = "Agents"; /*!< Persistent Agents astdb family */
216 #define PA_MAX_LEN 2048 /*!< The maximum length of each persistent member agent database entry */
218 #define DEFAULT_ACCEPTDTMF '#'
219 #define DEFAULT_ENDDTMF '*'
221 static ast_group_t group;
222 static int autologoff;
223 static int wrapuptime;
226 static int autologoffunavail = 0;
227 static char acceptdtmf = DEFAULT_ACCEPTDTMF;
228 static char enddtmf = DEFAULT_ENDDTMF;
230 static int maxlogintries = 3;
231 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
233 static int recordagentcalls = 0;
234 static char recordformat[AST_MAX_BUF] = "";
235 static char recordformatext[AST_MAX_BUF] = "";
236 static char urlprefix[AST_MAX_BUF] = "";
237 static char savecallsin[AST_MAX_BUF] = "";
238 static int updatecdr = 0;
239 static char beep[AST_MAX_BUF] = "beep";
241 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
244 AGENT_FLAG_ACKCALL = (1 << 0),
245 AGENT_FLAG_AUTOLOGOFF = (1 << 1),
246 AGENT_FLAG_WRAPUPTIME = (1 << 2),
247 AGENT_FLAG_ACCEPTDTMF = (1 << 3),
248 AGENT_FLAG_ENDDTMF = (1 << 4),
251 /*! \brief Structure representing an agent. */
253 ast_mutex_t lock; /*!< Channel private lock */
254 int dead; /*!< Poised for destruction? */
255 int pending; /*!< Not a real agent -- just pending a match */
256 int abouttograb; /*!< About to grab */
257 int autologoff; /*!< Auto timeout time */
258 int ackcall; /*!< ackcall */
259 int deferlogoff; /*!< Defer logoff to hangup */
262 time_t loginstart; /*!< When agent first logged in (0 when logged off) */
263 time_t start; /*!< When call started */
264 struct timeval lastdisc; /*!< When last disconnected */
265 int wrapuptime; /*!< Wrapup time in ms */
266 ast_group_t group; /*!< Group memberships */
267 int acknowledged; /*!< Acknowledged */
268 char moh[80]; /*!< Which music on hold */
269 char agent[AST_MAX_AGENT]; /*!< Agent ID */
270 char password[AST_MAX_AGENT]; /*!< Password for Agent login */
271 char name[AST_MAX_AGENT];
273 ast_cond_t app_complete_cond;
274 ast_cond_t login_wait_cond;
275 volatile int app_sleep_cond; /**< Sleep condition for the login app */
276 struct ast_channel *owner; /**< Agent */
277 char logincallerid[80]; /**< Caller ID they had when they logged in */
278 struct ast_channel *chan; /**< Channel we use */
279 unsigned int flags; /**< Flags show if settings were applied with channel vars */
280 AST_LIST_ENTRY(agent_pvt) list; /**< Next Agent in the linked list. */
283 #define DATA_EXPORT_AGENT(MEMBER) \
284 MEMBER(agent_pvt, autologoff, AST_DATA_INTEGER) \
285 MEMBER(agent_pvt, ackcall, AST_DATA_BOOLEAN) \
286 MEMBER(agent_pvt, deferlogoff, AST_DATA_BOOLEAN) \
287 MEMBER(agent_pvt, wrapuptime, AST_DATA_MILLISECONDS) \
288 MEMBER(agent_pvt, acknowledged, AST_DATA_BOOLEAN) \
289 MEMBER(agent_pvt, name, AST_DATA_STRING) \
290 MEMBER(agent_pvt, password, AST_DATA_PASSWORD) \
291 MEMBER(agent_pvt, acceptdtmf, AST_DATA_CHARACTER) \
292 MEMBER(agent_pvt, logincallerid, AST_DATA_STRING)
294 AST_DATA_STRUCTURE(agent_pvt, DATA_EXPORT_AGENT);
296 static AST_LIST_HEAD_STATIC(agents, agent_pvt); /*!< Holds the list of agents (loaded form agents.conf). */
298 #define CHECK_FORMATS(ast, p) do { \
300 if (!(ast_format_cap_identical(ast_channel_nativeformats(ast), ast_channel_nativeformats(p->chan)))) { \
301 char tmp1[256], tmp2[256]; \
302 ast_debug(1, "Native formats changing from '%s' to '%s'\n", ast_getformatname_multiple(tmp1, sizeof(tmp1), ast_channel_nativeformats(ast)), ast_getformatname_multiple(tmp2, sizeof(tmp2), ast_channel_nativeformats(p->chan))); \
303 /* Native formats changed, reset things */ \
304 ast_format_cap_copy(ast_channel_nativeformats(ast), ast_channel_nativeformats(p->chan)); \
305 ast_debug(1, "Resetting read to '%s' and write to '%s'\n", ast_getformatname(ast_channel_readformat(ast)), ast_getformatname(ast_channel_writeformat(ast)));\
306 ast_set_read_format(ast, ast_channel_readformat(ast)); \
307 ast_set_write_format(ast, ast_channel_writeformat(ast)); \
309 if ((ast_format_cmp(ast_channel_readformat(p->chan), ast_channel_rawreadformat(ast)) != AST_FORMAT_CMP_EQUAL) && !ast_channel_generator(p->chan)) \
310 ast_set_read_format(p->chan, ast_channel_rawreadformat(ast)); \
311 if ((ast_format_cmp(ast_channel_writeformat(p->chan), ast_channel_rawwriteformat(ast)) != AST_FORMAT_CMP_EQUAL) && !ast_channel_generator(p->chan)) \
312 ast_set_write_format(p->chan, ast_channel_rawwriteformat(ast)); \
316 /*! \brief Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
317 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
318 totally impractical combinations XXX */
320 #define CLEANUP(ast, p) do { \
323 for (x = 0; x < AST_MAX_FDS; x++) { \
324 if (x != AST_TIMING_FD) { \
325 ast_channel_set_fd(ast, x, ast_channel_fd(p->chan, x)); \
328 ast_channel_set_fd(ast, AST_AGENT_FD, ast_channel_fd(p->chan, AST_TIMING_FD)); \
332 /*--- Forward declarations */
333 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, const char *data, int *cause);
334 static int agent_devicestate(const char *data);
335 static int agent_digit_begin(struct ast_channel *ast, char digit);
336 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
337 static int agent_call(struct ast_channel *ast, const char *dest, int timeout);
338 static int agent_hangup(struct ast_channel *ast);
339 static int agent_answer(struct ast_channel *ast);
340 static struct ast_frame *agent_read(struct ast_channel *ast);
341 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
342 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
343 static int agent_sendtext(struct ast_channel *ast, const char *text);
344 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen);
345 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
346 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
347 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state);
348 static struct ast_channel* agent_get_base_channel(struct ast_channel *chan);
349 static int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base);
350 static int agent_logoff(const char *agent, int soft);
352 /*! \brief Channel interface description for PBX integration */
353 static struct ast_channel_tech agent_tech = {
355 .description = tdesc,
356 .requester = agent_request,
357 .devicestate = agent_devicestate,
358 .send_digit_begin = agent_digit_begin,
359 .send_digit_end = agent_digit_end,
361 .hangup = agent_hangup,
362 .answer = agent_answer,
364 .write = agent_write,
365 .write_video = agent_write,
366 .send_html = agent_sendhtml,
367 .send_text = agent_sendtext,
368 .exception = agent_read,
369 .indicate = agent_indicate,
370 .fixup = agent_fixup,
371 .bridged_channel = agent_bridgedchannel,
372 .get_base_channel = agent_get_base_channel,
373 .set_base_channel = agent_set_base_channel,
377 * \brief Locks the owning channel for a LOCKED pvt while obeying locking order. The pvt
378 * must enter this function locked and will be returned locked, but this function will
379 * unlock the pvt for a short time, so it can't be used while expecting the pvt to remain
380 * static. If function returns a non NULL channel, it will need to be unlocked and
381 * unrefed once it is no longer needed.
383 * \param pvt Pointer to the LOCKED agent_pvt for which the owner is needed
384 * locked channel which owns the pvt at the time of completion. NULL if not available.
386 static struct ast_channel *agent_lock_owner(struct agent_pvt *pvt)
388 struct ast_channel *owner;
391 if (!pvt->owner) { /* No owner. Nothing to do. */
395 /* If we don't ref the owner, it could be killed when we unlock the pvt. */
396 owner = ast_channel_ref(pvt->owner);
398 /* Locking order requires us to lock channel, then pvt. */
399 ast_mutex_unlock(&pvt->lock);
400 ast_channel_lock(owner);
401 ast_mutex_lock(&pvt->lock);
403 /* Check if owner changed during pvt unlock period */
404 if (owner != pvt->owner) { /* Channel changed. Unref and do another pass. */
405 ast_channel_unlock(owner);
406 owner = ast_channel_unref(owner);
407 } else { /* Channel stayed the same. Return it. */
414 * Adds an agent to the global list of agents.
416 * \param agent A string with the username, password and real name of an agent. As defined in agents.conf. Example: "13,169,John Smith"
417 * \param pending If it is pending or not.
418 * @return The just created agent.
419 * \sa agent_pvt, agents.
421 static struct agent_pvt *add_agent(const char *agent, int pending)
424 AST_DECLARE_APP_ARGS(args,
426 AST_APP_ARG(password);
429 char *password = NULL;
434 parse = ast_strdupa(agent);
436 /* Extract username (agt), password and name from agent (args). */
437 AST_STANDARD_APP_ARGS(args, parse);
440 ast_log(LOG_WARNING, "A blank agent line!\n");
444 if(ast_strlen_zero(args.agt) ) {
445 ast_log(LOG_WARNING, "An agent line with no agentid!\n");
450 if(!ast_strlen_zero(args.password)) {
451 password = args.password;
452 while (*password && *password < 33) password++;
454 if(!ast_strlen_zero(args.name)) {
456 while (*name && *name < 33) name++;
459 /* Are we searching for the agent here ? To see if it exists already ? */
460 AST_LIST_TRAVERSE(&agents, p, list) {
461 if (!pending && !strcmp(p->agent, agt))
466 if (!(p = ast_calloc(1, sizeof(*p))))
468 ast_copy_string(p->agent, agt, sizeof(p->agent));
469 ast_mutex_init(&p->lock);
470 ast_cond_init(&p->app_complete_cond, NULL);
471 ast_cond_init(&p->login_wait_cond, NULL);
472 p->app_lock_flag = 0;
473 p->app_sleep_cond = 1;
475 p->pending = pending;
476 AST_LIST_INSERT_TAIL(&agents, p, list);
479 ast_copy_string(p->password, password ? password : "", sizeof(p->password));
480 ast_copy_string(p->name, name ? name : "", sizeof(p->name));
481 ast_copy_string(p->moh, moh, sizeof(p->moh));
482 if (!ast_test_flag(p, AGENT_FLAG_ACKCALL)) {
483 p->ackcall = ackcall;
485 if (!ast_test_flag(p, AGENT_FLAG_AUTOLOGOFF)) {
486 p->autologoff = autologoff;
488 if (!ast_test_flag(p, AGENT_FLAG_ACCEPTDTMF)) {
489 p->acceptdtmf = acceptdtmf;
491 if (!ast_test_flag(p, AGENT_FLAG_ENDDTMF)) {
492 p->enddtmf = enddtmf;
495 /* If someone reduces the wrapuptime and reloads, we want it
496 * to change the wrapuptime immediately on all calls */
497 if (!ast_test_flag(p, AGENT_FLAG_WRAPUPTIME) && p->wrapuptime > wrapuptime) {
498 struct timeval now = ast_tvnow();
499 /* XXX check what is this exactly */
501 /* We won't be pedantic and check the tv_usec val */
502 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
503 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
504 p->lastdisc.tv_usec = now.tv_usec;
507 p->wrapuptime = wrapuptime;
517 * Deletes an agent after doing some clean up.
518 * Further documentation: How safe is this function ? What state should the agent be to be cleaned.
520 * \warning XXX This function seems to be very unsafe.
521 * Potential for double free and use after free among other
524 * \param p Agent to be deleted.
527 static int agent_cleanup(struct agent_pvt *p)
529 struct ast_channel *chan;
531 ast_mutex_lock(&p->lock);
534 /* Release ownership of the agent to other threads (presumably running the login app). */
535 p->app_sleep_cond = 1;
536 p->app_lock_flag = 0;
537 ast_cond_signal(&p->app_complete_cond);
539 ast_channel_tech_pvt_set(chan, NULL);
540 chan = ast_channel_release(chan);
543 ast_mutex_unlock(&p->lock);
544 ast_mutex_destroy(&p->lock);
545 ast_cond_destroy(&p->app_complete_cond);
546 ast_cond_destroy(&p->login_wait_cond);
549 ast_mutex_unlock(&p->lock);
554 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
556 static int agent_answer(struct ast_channel *ast)
558 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
562 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
564 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
565 char filename[AST_MAX_BUF];
569 if (!ast_channel_monitor(ast)) {
570 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast_channel_uniqueid(ast));
571 /* substitute . for - */
572 if ((pointer = strchr(filename, '.')))
574 snprintf(tmp, sizeof(tmp), "%s%s", savecallsin, filename);
575 ast_monitor_start(ast, recordformat, tmp, needlock, X_REC_IN | X_REC_OUT);
576 ast_monitor_setjoinfiles(ast, 1);
577 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix, filename, recordformatext);
579 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
581 if (!ast_channel_cdr(ast))
582 ast_channel_cdr_set(ast, ast_cdr_alloc());
583 ast_cdr_setuserfield(ast, tmp2);
586 ast_log(LOG_ERROR, "Recording already started on that call.\n");
590 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
592 return __agent_start_monitoring(ast, ast_channel_tech_pvt(ast), needlock);
595 static struct ast_frame *agent_read(struct ast_channel *ast)
597 struct agent_pvt *p = ast_channel_tech_pvt(ast);
598 struct ast_frame *f = NULL;
599 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, { AST_CONTROL_ANSWER } };
600 int cur_time = time(NULL);
601 struct ast_channel *owner;
603 ast_mutex_lock(&p->lock);
604 owner = agent_lock_owner(p);
606 CHECK_FORMATS(ast, p);
611 ast_copy_flags(ast_channel_flags(p->chan), ast_channel_flags(ast), AST_FLAG_EXCEPTION);
612 ast_channel_fdno_set(p->chan, (ast_channel_fdno(ast) == AST_AGENT_FD) ? AST_TIMING_FD : ast_channel_fdno(ast));
613 f = ast_read(p->chan);
617 /* If there's a channel, make it NULL */
619 ast_channel_internal_bridged_channel_set(p->chan, NULL);
621 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
625 /* if acknowledgement is not required, and the channel is up, we may have missed
626 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
627 if (!p->ackcall && !p->acknowledged && p->chan && (ast_channel_state(p->chan) == AST_STATE_UP)) {
631 if (!p->acknowledged) {
632 int howlong = cur_time - p->start;
633 if (p->autologoff && (howlong >= p->autologoff)) {
634 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
635 if (owner || p->chan) {
637 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
638 ast_channel_unlock(owner);
639 owner = ast_channel_unref(owner);
642 while (p->chan && ast_channel_trylock(p->chan)) {
643 DEADLOCK_AVOIDANCE(&p->lock);
646 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
647 ast_channel_unlock(p->chan);
652 switch (f->frametype) {
653 case AST_FRAME_CONTROL:
654 if (f->subclass.integer == AST_CONTROL_ANSWER) {
656 ast_verb(3, "%s answered, waiting for '%c' to acknowledge\n", ast_channel_name(p->chan), p->acceptdtmf);
657 /* Don't pass answer along */
662 /* Use the builtin answer frame for the
663 recording start check below. */
669 case AST_FRAME_DTMF_BEGIN:
670 /*ignore DTMF begin's as it can cause issues with queue announce files*/
671 if((!p->acknowledged && f->subclass.integer == p->acceptdtmf) || (f->subclass.integer == p->enddtmf && endcall)){
676 case AST_FRAME_DTMF_END:
677 if (!p->acknowledged && (f->subclass.integer == p->acceptdtmf)) {
679 ast_verb(3, "%s acknowledged\n", ast_channel_name(p->chan));
684 } else if (f->subclass.integer == p->enddtmf && endcall) {
685 /* terminates call */
690 case AST_FRAME_VOICE:
691 case AST_FRAME_VIDEO:
692 /* don't pass voice or video until the call is acknowledged */
693 if (!p->acknowledged) {
698 /* pass everything else on through */
704 ast_channel_unlock(owner);
705 owner = ast_channel_unref(owner);
709 if (p->chan && !ast_channel_internal_bridged_channel(p->chan)) {
710 if (strcasecmp(ast_channel_tech(p->chan)->type, "Local")) {
711 ast_channel_internal_bridged_channel_set(p->chan, ast);
713 ast_debug(1, "Bridge on '%s' being set to '%s' (3)\n", ast_channel_name(p->chan), ast_channel_name(ast_channel_internal_bridged_channel(p->chan)));
716 ast_mutex_unlock(&p->lock);
717 if (recordagentcalls && f == &answer_frame)
718 agent_start_monitoring(ast,0);
722 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
724 struct agent_pvt *p = ast_channel_tech_pvt(ast);
726 ast_mutex_lock(&p->lock);
728 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
729 ast_mutex_unlock(&p->lock);
733 static int agent_sendtext(struct ast_channel *ast, const char *text)
735 struct agent_pvt *p = ast_channel_tech_pvt(ast);
737 ast_mutex_lock(&p->lock);
739 res = ast_sendtext(p->chan, text);
740 ast_mutex_unlock(&p->lock);
744 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
746 struct agent_pvt *p = ast_channel_tech_pvt(ast);
748 CHECK_FORMATS(ast, p);
749 ast_mutex_lock(&p->lock);
753 if ((f->frametype != AST_FRAME_VOICE) ||
754 (f->frametype != AST_FRAME_VIDEO) ||
755 (ast_format_cmp(&f->subclass.format, ast_channel_writeformat(p->chan)) != AST_FORMAT_CMP_NOT_EQUAL)) {
756 res = ast_write(p->chan, f);
758 ast_debug(1, "Dropping one incompatible %s frame on '%s' to '%s'\n",
759 f->frametype == AST_FRAME_VOICE ? "audio" : "video",
760 ast_channel_name(ast), ast_channel_name(p->chan));
765 ast_mutex_unlock(&p->lock);
769 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
771 struct agent_pvt *p = ast_channel_tech_pvt(newchan);
772 ast_mutex_lock(&p->lock);
773 if (p->owner != oldchan) {
774 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
775 ast_mutex_unlock(&p->lock);
779 ast_mutex_unlock(&p->lock);
783 static int agent_indicate(struct ast_channel *ast, int condition, const void *data, size_t datalen)
785 struct agent_pvt *p = ast_channel_tech_pvt(ast);
787 ast_mutex_lock(&p->lock);
788 if (p->chan && !ast_check_hangup(p->chan)) {
789 while (ast_channel_trylock(p->chan)) {
790 if ((res = ast_channel_unlock(ast))) {
791 ast_log(LOG_ERROR, "chan_agent bug! Channel was not locked upon entry to agent_indicate: %s\n", res > 0 ? strerror(res) : "Bad ao2obj data");
792 ast_mutex_unlock(&p->lock);
796 ast_channel_lock(ast);
798 res = ast_channel_tech(p->chan)->indicate ? ast_channel_tech(p->chan)->indicate(p->chan, condition, data, datalen) : -1;
799 ast_channel_unlock(p->chan);
802 ast_mutex_unlock(&p->lock);
806 static int agent_digit_begin(struct ast_channel *ast, char digit)
808 struct agent_pvt *p = ast_channel_tech_pvt(ast);
809 ast_mutex_lock(&p->lock);
811 ast_senddigit_begin(p->chan, digit);
813 ast_mutex_unlock(&p->lock);
817 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
819 struct agent_pvt *p = ast_channel_tech_pvt(ast);
820 ast_mutex_lock(&p->lock);
822 ast_senddigit_end(p->chan, digit, duration);
824 ast_mutex_unlock(&p->lock);
828 static int agent_call(struct ast_channel *ast, const char *dest, int timeout)
830 struct agent_pvt *p = ast_channel_tech_pvt(ast);
833 struct ast_channel *chan;
835 ast_mutex_lock(&p->lock);
839 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
840 ast_mutex_unlock(&p->lock);
841 ast_setstate(ast, AST_STATE_DIALING);
846 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
847 ast_mutex_unlock(&p->lock);
850 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, ast_channel_name(p->chan));
851 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(p->chan));
854 ast_mutex_unlock(&p->lock);
856 res = ast_streamfile(chan, beep, ast_channel_language(chan));
857 ast_debug(3, "Played beep, result '%d'\n", res);
859 res = ast_waitstream(chan, "");
860 ast_debug(3, "Waited for stream, result '%d'\n", res);
863 ast_mutex_lock(&p->lock);
865 /* chan went away while we were streaming, this shouldn't be possible */
870 struct ast_format tmpfmt;
871 res = ast_set_read_format_from_cap(p->chan, ast_channel_nativeformats(p->chan));
872 ast_debug(3, "Set read format, result '%d'\n", res);
874 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
878 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
882 struct ast_format tmpfmt;
883 res = ast_set_write_format_from_cap(p->chan, ast_channel_nativeformats(p->chan));
884 ast_debug(3, "Set write format, result '%d'\n", res);
886 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
889 /* Call is immediately up, or might need ack */
891 newstate = AST_STATE_RINGING;
893 newstate = AST_STATE_UP;
894 if (recordagentcalls)
895 agent_start_monitoring(ast, 0);
901 ast_mutex_unlock(&p->lock);
903 ast_setstate(ast, newstate);
907 /*! \brief return the channel or base channel if one exists. This function assumes the channel it is called on is already locked */
908 struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
910 struct agent_pvt *p = NULL;
911 struct ast_channel *base = chan;
913 /* chan is locked by the calling function */
914 if (!chan || !ast_channel_tech_pvt(chan)) {
915 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)ast_channel_tech_pvt(chan):(long)NULL);
918 p = ast_channel_tech_pvt(chan);
924 int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
926 struct agent_pvt *p = NULL;
928 if (!chan || !base) {
929 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
932 p = ast_channel_tech_pvt(chan);
934 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", ast_channel_name(chan));
941 static int agent_hangup(struct ast_channel *ast)
943 struct agent_pvt *p = ast_channel_tech_pvt(ast);
944 struct ast_channel *indicate_chan = NULL;
945 char *tmp_moh; /* moh buffer for indicating after unlocking p */
948 AST_LIST_LOCK(&agents);
949 AST_LIST_REMOVE(&agents, p, list);
950 AST_LIST_UNLOCK(&agents);
953 ast_mutex_lock(&p->lock);
955 ast_channel_tech_pvt_set(ast, NULL);
956 p->app_sleep_cond = 1;
959 /* Release ownership of the agent to other threads (presumably running the login app). */
960 p->app_lock_flag = 0;
961 ast_cond_signal(&p->app_complete_cond);
963 /* if they really are hung up then set start to 0 so the test
964 * later if we're called on an already downed channel
965 * doesn't cause an agent to be logged out like when
966 * agent_request() is followed immediately by agent_hangup()
967 * as in apps/app_chanisavail.c:chanavail_exec()
970 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast_channel_state(ast)));
971 if (p->start && (ast_channel_state(ast) != AST_STATE_UP)) {
976 ast_channel_internal_bridged_channel_set(p->chan, NULL);
977 /* If they're dead, go ahead and hang up on the agent now */
979 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
980 } else if (p->loginstart) {
981 indicate_chan = ast_channel_ref(p->chan);
982 tmp_moh = ast_strdupa(p->moh);
985 ast_mutex_unlock(&p->lock);
988 ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
990 !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
991 indicate_chan = ast_channel_unref(indicate_chan);
994 /* Only register a device state change if the agent is still logged in */
995 if (!p->loginstart) {
996 p->logincallerid[0] = '\0';
998 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
1001 if (p->abouttograb) {
1002 /* Let the "about to grab" thread know this isn't valid anymore, and let it
1005 } else if (p->dead) {
1006 ast_mutex_destroy(&p->lock);
1007 ast_cond_destroy(&p->app_complete_cond);
1008 ast_cond_destroy(&p->login_wait_cond);
1012 /* Not dead -- check availability now */
1013 ast_mutex_lock(&p->lock);
1014 /* Store last disconnect time */
1015 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
1016 ast_mutex_unlock(&p->lock);
1022 static int agent_cont_sleep( void *data )
1024 struct agent_pvt *p;
1027 p = (struct agent_pvt *)data;
1029 ast_mutex_lock(&p->lock);
1030 res = p->app_sleep_cond;
1031 if (p->lastdisc.tv_sec) {
1032 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0)
1035 ast_mutex_unlock(&p->lock);
1038 ast_debug(5, "agent_cont_sleep() returning %d\n", res );
1043 static int agent_ack_sleep(void *data)
1045 struct agent_pvt *p;
1048 struct ast_frame *f;
1049 struct timeval start = ast_tvnow();
1052 /* Wait a second and look for something */
1054 p = (struct agent_pvt *) data;
1058 while ((ms = ast_remaining_ms(start, to))) {
1059 ms = ast_waitfor(p->chan, ms);
1066 f = ast_read(p->chan);
1069 if (f->frametype == AST_FRAME_DTMF)
1070 res = f->subclass.integer;
1074 ast_mutex_lock(&p->lock);
1075 if (!p->app_sleep_cond) {
1076 ast_mutex_unlock(&p->lock);
1078 } else if (res == p->acceptdtmf) {
1079 ast_mutex_unlock(&p->lock);
1082 ast_mutex_unlock(&p->lock);
1088 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
1090 struct agent_pvt *p = ast_channel_tech_pvt(bridge);
1091 struct ast_channel *ret = NULL;
1094 if (chan == p->chan)
1095 ret = ast_channel_internal_bridged_channel(bridge);
1096 else if (chan == ast_channel_internal_bridged_channel(bridge))
1100 ast_debug(1, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", ast_channel_name(chan), ast_channel_name(bridge), ret ? ast_channel_name(ret) : "<none>");
1104 /*! \brief Create new agent channel */
1105 static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char *linkedid, struct ast_callid *callid)
1107 struct ast_channel *tmp;
1110 ast_log(LOG_WARNING, "No channel? :(\n");
1115 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? ast_channel_exten(p->chan):"", p->chan ? ast_channel_context(p->chan):"", linkedid, 0, "Agent/P%s-%d", p->agent, (int) ast_random() & 0xffff);
1117 tmp = ast_channel_alloc(0, state, 0, 0, "", p->chan ? ast_channel_exten(p->chan):"", p->chan ? ast_channel_context(p->chan):"", linkedid, 0, "Agent/%s", p->agent);
1119 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
1124 ast_channel_callid_set(tmp, callid);
1127 ast_channel_tech_set(tmp, &agent_tech);
1129 ast_format_cap_copy(ast_channel_nativeformats(tmp), ast_channel_nativeformats(p->chan));
1130 ast_format_copy(ast_channel_writeformat(tmp), ast_channel_writeformat(p->chan));
1131 ast_format_copy(ast_channel_rawwriteformat(tmp), ast_channel_writeformat(p->chan));
1132 ast_format_copy(ast_channel_readformat(tmp), ast_channel_readformat(p->chan));
1133 ast_format_copy(ast_channel_rawreadformat(tmp), ast_channel_readformat(p->chan));
1134 ast_channel_language_set(tmp, ast_channel_language(p->chan));
1135 ast_channel_context_set(tmp, ast_channel_context(p->chan));
1136 ast_channel_exten_set(tmp, ast_channel_exten(p->chan));
1137 /* XXX Is this really all we copy form the originating channel?? */
1139 ast_format_set(ast_channel_writeformat(tmp), AST_FORMAT_SLINEAR, 0);
1140 ast_format_set(ast_channel_rawwriteformat(tmp), AST_FORMAT_SLINEAR, 0);
1141 ast_format_set(ast_channel_readformat(tmp), AST_FORMAT_SLINEAR, 0);
1142 ast_format_set(ast_channel_rawreadformat(tmp), AST_FORMAT_SLINEAR, 0);
1143 ast_format_cap_add(ast_channel_nativeformats(tmp), ast_channel_writeformat(tmp));
1145 /* Safe, agentlock already held */
1146 ast_channel_tech_pvt_set(tmp, p);
1148 ast_channel_priority_set(tmp, 1);
1154 * Read configuration data. The file named agents.conf.
1156 * \returns Always 0, or so it seems.
1158 static int read_agent_config(int reload)
1160 struct ast_config *cfg;
1161 struct ast_config *ucfg;
1162 struct ast_variable *v;
1163 struct agent_pvt *p;
1164 const char *catname;
1165 const char *hasagent;
1167 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1174 cfg = ast_config_load(config, config_flags);
1176 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1178 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1180 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1181 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config);
1184 if ((ucfg = ast_config_load("users.conf", config_flags))) {
1185 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
1187 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
1188 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n");
1193 AST_LIST_LOCK(&agents);
1194 AST_LIST_TRAVERSE(&agents, p, list) {
1197 strcpy(moh, "default");
1198 /* set the default recording values */
1199 recordagentcalls = 0;
1200 strcpy(recordformat, "wav");
1201 strcpy(recordformatext, "wav");
1202 urlprefix[0] = '\0';
1203 savecallsin[0] = '\0';
1205 /* Read in the [agents] section */
1206 v = ast_variable_browse(cfg, "agents");
1208 /* Create the interface list */
1209 if (!strcasecmp(v->name, "agent")) {
1210 add_agent(v->value, 0);
1211 } else if (!strcasecmp(v->name, "group")) {
1212 group = ast_get_group(v->value);
1213 } else if (!strcasecmp(v->name, "autologoff")) {
1214 autologoff = atoi(v->value);
1217 } else if (!strcasecmp(v->name, "ackcall")) {
1218 if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
1221 } else if (!strcasecmp(v->name, "endcall")) {
1222 endcall = ast_true(v->value);
1223 } else if (!strcasecmp(v->name, "acceptdtmf")) {
1224 acceptdtmf = *(v->value);
1225 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
1226 } else if (!strcasecmp(v->name, "enddtmf")) {
1227 enddtmf = *(v->value);
1228 } else if (!strcasecmp(v->name, "wrapuptime")) {
1229 wrapuptime = atoi(v->value);
1232 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1233 maxlogintries = atoi(v->value);
1234 if (maxlogintries < 0)
1236 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1237 strcpy(agentgoodbye,v->value);
1238 } else if (!strcasecmp(v->name, "musiconhold")) {
1239 ast_copy_string(moh, v->value, sizeof(moh));
1240 } else if (!strcasecmp(v->name, "updatecdr")) {
1241 if (ast_true(v->value))
1245 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1246 if (ast_true(v->value))
1247 autologoffunavail = 1;
1249 autologoffunavail = 0;
1250 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1251 recordagentcalls = ast_true(v->value);
1252 } else if (!strcasecmp(v->name, "recordformat")) {
1253 ast_copy_string(recordformat, v->value, sizeof(recordformat));
1254 if (!strcasecmp(v->value, "wav49"))
1255 strcpy(recordformatext, "WAV");
1257 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1258 } else if (!strcasecmp(v->name, "urlprefix")) {
1259 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1260 if (urlprefix[strlen(urlprefix) - 1] != '/')
1261 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1262 } else if (!strcasecmp(v->name, "savecallsin")) {
1263 if (v->value[0] == '/')
1264 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1266 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1267 if (savecallsin[strlen(savecallsin) - 1] != '/')
1268 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1269 } else if (!strcasecmp(v->name, "custom_beep")) {
1270 ast_copy_string(beep, v->value, sizeof(beep));
1275 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1276 catname = ast_category_browse(ucfg, NULL);
1278 if (strcasecmp(catname, "general")) {
1279 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1280 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1282 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1283 const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1288 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1292 catname = ast_category_browse(ucfg, catname);
1294 ast_config_destroy(ucfg);
1296 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1298 AST_LIST_REMOVE_CURRENT(list);
1299 /* Destroy if appropriate */
1302 ast_mutex_destroy(&p->lock);
1303 ast_cond_destroy(&p->app_complete_cond);
1304 ast_cond_destroy(&p->login_wait_cond);
1307 /* Cause them to hang up */
1308 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1313 AST_LIST_TRAVERSE_SAFE_END;
1314 AST_LIST_UNLOCK(&agents);
1315 ast_config_destroy(cfg);
1319 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1321 struct ast_channel *chan=NULL, *parent=NULL;
1322 struct agent_pvt *p;
1325 ast_debug(1, "Checking 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 winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1335 /* We found a pending call, time to merge */
1336 chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? ast_channel_linkedid(p->owner) : NULL, NULL);
1339 ast_mutex_unlock(&p->lock);
1342 ast_mutex_unlock(&p->lock);
1345 AST_LIST_UNLOCK(&agents);
1346 if (parent && chan) {
1347 if (newlyavailable->ackcall) {
1348 /* Don't do beep here */
1351 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1352 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1353 ast_debug(3, "Played beep, result '%d'\n", res);
1355 res = ast_waitstream(newlyavailable->chan, "");
1356 ast_debug(1, "Waited for stream, result '%d'\n", res);
1360 /* Note -- parent may have disappeared */
1361 if (p->abouttograb) {
1362 newlyavailable->acknowledged = 1;
1363 /* Safe -- agent lock already held */
1364 ast_setstate(parent, AST_STATE_UP);
1365 ast_setstate(chan, AST_STATE_UP);
1366 ast_channel_context_set(parent, ast_channel_context(chan));
1367 ast_channel_masquerade(parent, chan);
1371 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1372 agent_cleanup(newlyavailable);
1375 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n");
1376 agent_cleanup(newlyavailable);
1382 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1384 struct agent_pvt *p;
1387 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1389 AST_LIST_LOCK(&agents);
1390 AST_LIST_TRAVERSE(&agents, p, list) {
1391 if (p == newlyavailable) {
1394 ast_mutex_lock(&p->lock);
1395 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1396 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1397 ast_mutex_unlock(&p->lock);
1400 ast_mutex_unlock(&p->lock);
1403 AST_LIST_UNLOCK(&agents);
1405 ast_mutex_unlock(&newlyavailable->lock);
1406 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1407 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1408 ast_debug(1, "Played beep, result '%d'\n", res);
1410 res = ast_waitstream(newlyavailable->chan, "");
1411 ast_debug(1, "Waited for stream, result '%d'\n", res);
1413 ast_mutex_lock(&newlyavailable->lock);
1418 /*! \brief Part of the Asterisk PBX interface */
1419 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel* requestor, const char *data, int *cause)
1421 struct agent_pvt *p;
1422 struct ast_channel *chan = NULL;
1424 ast_group_t groupmatch;
1429 struct ast_callid *callid = ast_read_threadstorage_callid();
1432 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1433 groupmatch = (1 << groupoff);
1434 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1435 groupmatch = (1 << groupoff);
1440 /* Check actual logged in agents first */
1441 AST_LIST_LOCK(&agents);
1442 AST_LIST_TRAVERSE(&agents, p, list) {
1443 ast_mutex_lock(&p->lock);
1444 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1449 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1450 p->lastdisc = ast_tv(0, 0);
1451 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1452 if (!p->owner && p->chan) {
1454 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
1457 ast_mutex_unlock(&p->lock);
1462 ast_mutex_unlock(&p->lock);
1465 if (!chan && waitforagent) {
1466 /* No agent available -- but we're requesting to wait for one.
1467 Allocate a place holder */
1469 ast_debug(1, "Creating place holder for '%s'\n", s);
1470 p = add_agent(data, 1);
1471 p->group = groupmatch;
1472 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
1474 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1476 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1479 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1480 AST_LIST_UNLOCK(&agents);
1483 callid = ast_callid_unref(callid);
1487 ast_mutex_lock(&p->lock);
1489 ast_mutex_unlock(&p->lock);
1494 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1495 *cause = AST_CAUSE_UNREGISTERED;
1496 ast_mutex_unlock(&p->lock);
1501 /* we need to take control of the channel from the login app
1503 p->app_sleep_cond = 0;
1504 p->app_lock_flag = 1;
1506 ast_queue_frame(p->chan, &ast_null_frame);
1507 ast_cond_wait(&p->login_wait_cond, &p->lock);
1510 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1511 p->app_sleep_cond = 1;
1512 p->app_lock_flag = 0;
1513 ast_cond_signal(&p->app_complete_cond);
1514 ast_mutex_unlock(&p->lock);
1515 *cause = AST_CAUSE_UNREGISTERED;
1520 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
1521 ast_mutex_unlock(&p->lock);
1527 static force_inline int powerof(unsigned int d)
1538 * Lists agents and their status to the Manager API.
1539 * It is registered on load_module() and it gets called by the manager backend.
1540 * This function locks both the pvt and the channel that owns it for a while, but
1541 * does not keep these locks.
1545 * \sa action_agent_logoff(), load_module().
1547 static int action_agents(struct mansession *s, const struct message *m)
1549 const char *id = astman_get_header(m,"ActionID");
1550 char idText[256] = "";
1551 struct agent_pvt *p;
1552 char *username = NULL;
1553 char *loginChan = NULL;
1554 char *talkingto = NULL;
1555 char *talkingtoChan = NULL;
1556 char *status = NULL;
1557 struct ast_channel *bridge;
1559 if (!ast_strlen_zero(id))
1560 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1561 astman_send_ack(s, m, "Agents will follow");
1562 AST_LIST_LOCK(&agents);
1563 AST_LIST_TRAVERSE(&agents, p, list) {
1564 struct ast_channel *owner;
1565 ast_mutex_lock(&p->lock);
1566 owner = agent_lock_owner(p);
1569 AGENT_LOGGEDOFF - Agent isn't logged in
1570 AGENT_IDLE - Agent is logged in, and waiting for call
1571 AGENT_ONCALL - Agent is logged in, and on a call
1572 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1574 username = S_OR(p->name, "None");
1576 /* Set a default status. It 'should' get changed. */
1577 status = "AGENT_UNKNOWN";
1580 loginChan = ast_strdupa(ast_channel_name(p->chan));
1581 if (owner && ast_channel_internal_bridged_channel(owner)) {
1582 talkingto = S_COR(ast_channel_caller(p->chan)->id.number.valid,
1583 ast_channel_caller(p->chan)->id.number.str, "n/a");
1584 if ((bridge = ast_bridged_channel(owner))) {
1585 talkingtoChan = ast_strdupa(ast_channel_name(bridge));
1587 talkingtoChan = "n/a";
1589 status = "AGENT_ONCALL";
1592 talkingtoChan = "n/a";
1593 status = "AGENT_IDLE";
1598 talkingtoChan = "n/a";
1599 status = "AGENT_LOGGEDOFF";
1603 ast_channel_unlock(owner);
1604 owner = ast_channel_unref(owner);
1607 astman_append(s, "Event: Agents\r\n"
1611 "LoggedInChan: %s\r\n"
1612 "LoggedInTime: %d\r\n"
1614 "TalkingToChan: %s\r\n"
1617 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1618 ast_mutex_unlock(&p->lock);
1620 AST_LIST_UNLOCK(&agents);
1621 astman_append(s, "Event: AgentsComplete\r\n"
1627 static int agent_logoff(const char *agent, int soft)
1629 struct agent_pvt *p;
1630 int ret = -1; /* Return -1 if no agent if found */
1632 AST_LIST_LOCK(&agents);
1633 AST_LIST_TRAVERSE(&agents, p, list) {
1634 if (!strcasecmp(p->agent, agent)) {
1636 if (p->owner || p->chan) {
1638 struct ast_channel *owner;
1639 ast_mutex_lock(&p->lock);
1640 owner = agent_lock_owner(p);
1643 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
1644 ast_channel_unlock(owner);
1645 owner = ast_channel_unref(owner);
1648 while (p->chan && ast_channel_trylock(p->chan)) {
1649 DEADLOCK_AVOIDANCE(&p->lock);
1652 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1653 ast_channel_unlock(p->chan);
1656 ast_mutex_unlock(&p->lock);
1663 AST_LIST_UNLOCK(&agents);
1668 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1675 e->command = "agent logoff";
1677 "Usage: agent logoff <channel> [soft]\n"
1678 " Sets an agent as no longer logged in.\n"
1679 " If 'soft' is specified, do not hangup existing calls.\n";
1682 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n);
1685 if (a->argc < 3 || a->argc > 4)
1686 return CLI_SHOWUSAGE;
1687 if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
1688 return CLI_SHOWUSAGE;
1690 agent = a->argv[2] + 6;
1691 ret = agent_logoff(agent, a->argc == 4);
1693 ast_cli(a->fd, "Logging out %s\n", agent);
1699 * Sets an agent as no longer logged in in the Manager API.
1700 * It is registered on load_module() and it gets called by the manager backend.
1704 * \sa action_agents(), load_module().
1706 static int action_agent_logoff(struct mansession *s, const struct message *m)
1708 const char *agent = astman_get_header(m, "Agent");
1709 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1711 int ret; /* return value of agent_logoff */
1713 if (ast_strlen_zero(agent)) {
1714 astman_send_error(s, m, "No agent specified");
1718 soft = ast_true(soft_s) ? 1 : 0;
1719 ret = agent_logoff(agent, soft);
1721 astman_send_ack(s, m, "Agent logged out");
1723 astman_send_error(s, m, "No such agent");
1728 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1733 struct agent_pvt *p;
1734 char name[AST_MAX_AGENT];
1735 int which = 0, len = strlen(word);
1737 AST_LIST_LOCK(&agents);
1738 AST_LIST_TRAVERSE(&agents, p, list) {
1739 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1740 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
1741 ret = ast_strdup(name);
1745 AST_LIST_UNLOCK(&agents);
1746 } else if (pos == 3 && state == 0)
1747 return ast_strdup("soft");
1753 * Show agents in cli.
1755 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1757 struct agent_pvt *p;
1758 char username[AST_MAX_BUF];
1759 char location[AST_MAX_BUF] = "";
1760 char talkingto[AST_MAX_BUF] = "";
1761 char music[AST_MAX_BUF];
1762 int count_agents = 0; /*!< Number of agents configured */
1763 int online_agents = 0; /*!< Number of online agents */
1764 int offline_agents = 0; /*!< Number of offline agents */
1768 e->command = "agent show";
1770 "Usage: agent show\n"
1771 " Provides summary information on agents.\n";
1778 return CLI_SHOWUSAGE;
1780 AST_LIST_LOCK(&agents);
1781 AST_LIST_TRAVERSE(&agents, p, list) {
1782 struct ast_channel *owner;
1783 ast_mutex_lock(&p->lock);
1784 owner = agent_lock_owner(p);
1787 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
1789 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
1791 if (!ast_strlen_zero(p->name))
1792 snprintf(username, sizeof(username), "(%s) ", p->name);
1796 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1797 if (owner && ast_bridged_channel(owner)) {
1798 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1800 strcpy(talkingto, " is idle");
1804 strcpy(location, "not logged in");
1805 talkingto[0] = '\0';
1808 if (!ast_strlen_zero(p->moh))
1809 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1810 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent,
1811 username, location, talkingto, music);
1816 ast_channel_unlock(owner);
1817 owner = ast_channel_unref(owner);
1819 ast_mutex_unlock(&p->lock);
1821 AST_LIST_UNLOCK(&agents);
1822 if ( !count_agents )
1823 ast_cli(a->fd, "No Agents are configured in %s\n",config);
1825 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1826 ast_cli(a->fd, "\n");
1832 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1834 struct agent_pvt *p;
1835 char username[AST_MAX_BUF];
1836 char location[AST_MAX_BUF] = "";
1837 char talkingto[AST_MAX_BUF] = "";
1838 char music[AST_MAX_BUF];
1839 int count_agents = 0; /* Number of agents configured */
1840 int online_agents = 0; /* Number of online agents */
1841 int agent_status = 0; /* 0 means offline, 1 means online */
1845 e->command = "agent show online";
1847 "Usage: agent show online\n"
1848 " Provides a list of all online agents.\n";
1855 return CLI_SHOWUSAGE;
1857 AST_LIST_LOCK(&agents);
1858 AST_LIST_TRAVERSE(&agents, p, list) {
1859 struct ast_channel *owner;
1861 agent_status = 0; /* reset it to offline */
1862 ast_mutex_lock(&p->lock);
1863 owner = agent_lock_owner(p);
1865 if (!ast_strlen_zero(p->name))
1866 snprintf(username, sizeof(username), "(%s) ", p->name);
1870 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1871 if (p->owner && ast_bridged_channel(p->owner)) {
1872 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1874 strcpy(talkingto, " is idle");
1881 ast_channel_unlock(owner);
1882 owner = ast_channel_unref(owner);
1885 if (!ast_strlen_zero(p->moh))
1886 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1888 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
1890 ast_mutex_unlock(&p->lock);
1892 AST_LIST_UNLOCK(&agents);
1894 ast_cli(a->fd, "No Agents are configured in %s\n", config);
1896 ast_cli(a->fd, "%d agents online\n", online_agents);
1897 ast_cli(a->fd, "\n");
1901 static const char agent_logoff_usage[] =
1902 "Usage: agent logoff <channel> [soft]\n"
1903 " Sets an agent as no longer logged in.\n"
1904 " If 'soft' is specified, do not hangup existing calls.\n";
1906 static struct ast_cli_entry cli_agents[] = {
1907 AST_CLI_DEFINE(agents_show, "Show status of agents"),
1908 AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
1909 AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
1913 * Called by the AgentLogin application (from the dial plan).
1915 * \brief Log in agent application.
1920 * \sa agentmonitoroutgoing_exec(), load_module().
1922 static int login_exec(struct ast_channel *chan, const char *data)
1926 int max_login_tries = maxlogintries;
1927 struct agent_pvt *p;
1928 struct ast_module_user *u;
1929 char user[AST_MAX_AGENT] = "";
1930 char pass[AST_MAX_AGENT];
1931 char agent[AST_MAX_AGENT] = "";
1932 char xpass[AST_MAX_AGENT] = "";
1935 AST_DECLARE_APP_ARGS(args,
1936 AST_APP_ARG(agent_id);
1937 AST_APP_ARG(options);
1938 AST_APP_ARG(extension);
1940 const char *tmpoptions = NULL;
1941 int play_announcement = 1;
1942 char agent_goodbye[AST_MAX_FILENAME_LEN];
1943 int update_cdr = updatecdr;
1944 char *filename = "agent-loginok";
1946 u = ast_module_user_add(chan);
1948 parse = ast_strdupa(data);
1950 AST_STANDARD_APP_ARGS(args, parse);
1952 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1954 ast_channel_lock(chan);
1955 /* Set Channel Specific Login Overrides */
1956 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1957 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1958 if (max_login_tries < 0)
1959 max_login_tries = 0;
1960 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1961 ast_verb(3, "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,ast_channel_name(chan));
1963 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1964 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1968 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1969 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,ast_channel_name(chan));
1971 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1972 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1973 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1974 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,ast_channel_name(chan));
1976 ast_channel_unlock(chan);
1977 /* End Channel Specific Login Overrides */
1979 if (!ast_strlen_zero(args.options)) {
1980 if (strchr(args.options, 's')) {
1981 play_announcement = 0;
1985 if (ast_channel_state(chan) != AST_STATE_UP)
1986 res = ast_answer(chan);
1988 if (!ast_strlen_zero(args.agent_id))
1989 ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1991 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1993 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1995 /* Check for password */
1996 AST_LIST_LOCK(&agents);
1997 AST_LIST_TRAVERSE(&agents, p, list) {
1998 if (!strcmp(p->agent, user) && !p->pending)
1999 ast_copy_string(xpass, p->password, sizeof(xpass));
2001 AST_LIST_UNLOCK(&agents);
2003 if (!ast_strlen_zero(xpass))
2004 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
2008 errmsg = "agent-incorrect";
2011 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
2014 /* Check again for accuracy */
2015 AST_LIST_LOCK(&agents);
2016 AST_LIST_TRAVERSE(&agents, p, list) {
2017 int unlock_channel = 1;
2018 ast_channel_lock(chan);
2019 ast_mutex_lock(&p->lock);
2020 if (!strcmp(p->agent, user) &&
2021 !strcmp(p->password, pass) && !p->pending) {
2023 /* Ensure we can't be gotten until we're done */
2024 p->lastdisc = ast_tvnow();
2025 p->lastdisc.tv_sec++;
2027 /* Set Channel Specific Agent Overrides */
2028 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2029 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2034 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2035 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
2036 ast_set_flag(p, AGENT_FLAG_ACKCALL);
2038 p->ackcall = ackcall;
2040 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
2041 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
2042 if (p->autologoff < 0)
2044 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2045 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
2046 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
2048 p->autologoff = autologoff;
2050 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
2051 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
2052 if (p->wrapuptime < 0)
2054 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2055 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
2056 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
2058 p->wrapuptime = wrapuptime;
2060 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2061 if (!ast_strlen_zero(tmpoptions)) {
2062 p->acceptdtmf = *tmpoptions;
2063 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
2064 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
2066 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
2067 if (!ast_strlen_zero(tmpoptions)) {
2068 p->enddtmf = *tmpoptions;
2069 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
2070 ast_set_flag(p, AGENT_FLAG_ENDDTMF);
2072 ast_channel_unlock(chan);
2074 /* End Channel Specific Agent Overrides */
2077 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
2079 p->logincallerid[0] = '\0';
2080 p->acknowledged = 0;
2082 ast_mutex_unlock(&p->lock);
2083 AST_LIST_UNLOCK(&agents);
2084 if( !res && play_announcement==1 )
2085 res = ast_streamfile(chan, filename, ast_channel_language(chan));
2087 ast_waitstream(chan, "");
2088 AST_LIST_LOCK(&agents);
2089 ast_mutex_lock(&p->lock);
2091 struct ast_format tmpfmt;
2092 res = ast_set_read_format_from_cap(chan, ast_channel_nativeformats(chan));
2094 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
2098 struct ast_format tmpfmt;
2099 res = ast_set_write_format_from_cap(chan, ast_channel_nativeformats(chan));
2101 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
2104 /* Check once more just in case */
2108 ast_indicate_data(chan, AST_CONTROL_HOLD,
2110 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2111 if (p->loginstart == 0)
2112 time(&p->loginstart);
2114 <managerEventInstance>
2115 <synopsis>Raised when an Agent has logged in.</synopsis>
2117 <parameter name="Agent">
2118 <para>The name of the agent.</para>
2122 <ref type="application">AgentLogin</ref>
2123 <ref type="managerEvent">Agentlogoff</ref>
2125 </managerEventInstance>
2127 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2131 p->agent, ast_channel_name(chan), ast_channel_uniqueid(chan));
2132 if (update_cdr && ast_channel_cdr(chan))
2133 snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "Agent/%s", p->agent);
2134 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGIN", "%s", ast_channel_name(chan));
2135 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
2136 ast_getformatname(ast_channel_readformat(chan)), ast_getformatname(ast_channel_writeformat(chan)));
2137 /* Login this channel and wait for it to go away */
2142 check_availability(p, 0);
2144 ast_mutex_unlock(&p->lock);
2145 AST_LIST_UNLOCK(&agents);
2146 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2148 ast_mutex_lock(&p->lock);
2149 if (p->deferlogoff && p->chan) {
2150 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
2153 if (p->chan != chan)
2155 ast_mutex_unlock(&p->lock);
2156 /* Yield here so other interested threads can kick in. */
2161 AST_LIST_LOCK(&agents);
2162 ast_mutex_lock(&p->lock);
2163 if (p->lastdisc.tv_sec) {
2164 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
2165 ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
2166 p->lastdisc = ast_tv(0, 0);
2167 ast_devstate_changed(AST_DEVICE_NOT_INUSE, "Agent/%s", p->agent);
2171 check_availability(p, 0);
2175 ast_mutex_unlock(&p->lock);
2176 AST_LIST_UNLOCK(&agents);
2178 /* Synchronize channel ownership between call to agent and itself. */
2179 ast_mutex_lock(&p->lock);
2180 if (p->app_lock_flag == 1) {
2181 ast_cond_signal(&p->login_wait_cond);
2182 ast_cond_wait(&p->app_complete_cond, &p->lock);
2184 ast_mutex_unlock(&p->lock);
2186 res = agent_ack_sleep(p);
2188 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2190 if (p->ackcall && (res == 1)) {
2191 AST_LIST_LOCK(&agents);
2192 ast_mutex_lock(&p->lock);
2193 check_availability(p, 0);
2194 ast_mutex_unlock(&p->lock);
2195 AST_LIST_UNLOCK(&agents);
2200 ast_mutex_lock(&p->lock);
2201 /* Log us off if appropriate */
2202 if (p->chan == chan) {
2206 /* Synchronize channel ownership between call to agent and itself. */
2207 if (p->app_lock_flag == 1) {
2208 ast_cond_signal(&p->login_wait_cond);
2209 ast_cond_wait(&p->app_complete_cond, &p->lock);
2212 if (res && p->owner)
2213 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
2215 p->acknowledged = 0;
2216 logintime = time(NULL) - p->loginstart;
2218 ast_mutex_unlock(&p->lock);
2220 <managerEventInstance>
2221 <synopsis>Raised when an Agent has logged off.</synopsis>
2223 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Agentlogin']/managerEventInstance/syntax/parameter[@name='Agent'])" />
2226 <ref type="managerEvent">Agentlogin</ref>
2228 </managerEventInstance>
2230 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2232 "Logintime: %ld\r\n"
2234 p->agent, logintime, ast_channel_uniqueid(chan));
2235 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGOFF", "%s|%ld", ast_channel_name(chan), logintime);
2236 ast_verb(2, "Agent '%s' logged out\n", p->agent);
2237 /* If there is no owner, go ahead and kill it now */
2238 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, "Agent/%s", p->agent);
2239 if (p->dead && !p->owner) {
2240 ast_mutex_destroy(&p->lock);
2241 ast_cond_destroy(&p->app_complete_cond);
2242 ast_cond_destroy(&p->login_wait_cond);
2247 ast_mutex_unlock(&p->lock);
2252 ast_mutex_unlock(&p->lock);
2253 errmsg = "agent-alreadyon";
2258 ast_mutex_unlock(&p->lock);
2259 if (unlock_channel) {
2260 ast_channel_unlock(chan);
2264 AST_LIST_UNLOCK(&agents);
2266 if (!res && (max_login_tries==0 || tries < max_login_tries))
2267 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2271 res = ast_safe_sleep(chan, 500);
2273 ast_module_user_remove(u);
2279 * \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2284 * \sa login_exec(), load_module().
2286 static int agentmonitoroutgoing_exec(struct ast_channel *chan, const char *data)
2288 int exitifnoagentid = 0;
2290 int changeoutgoing = 0;
2292 char agent[AST_MAX_AGENT];
2295 if (strchr(data, 'd'))
2296 exitifnoagentid = 1;
2297 if (strchr(data, 'n'))
2299 if (strchr(data, 'c'))
2302 if (ast_channel_caller(chan)->id.number.valid
2303 && !ast_strlen_zero(ast_channel_caller(chan)->id.number.str)) {
2305 char agentvar[AST_MAX_BUF];
2306 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
2307 ast_channel_caller(chan)->id.number.str);
2308 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2309 struct agent_pvt *p;
2310 ast_copy_string(agent, tmp, sizeof(agent));
2311 AST_LIST_LOCK(&agents);
2312 AST_LIST_TRAVERSE(&agents, p, list) {
2313 if (!strcasecmp(p->agent, tmp)) {
2314 if (changeoutgoing) snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "Agent/%s", p->agent);
2315 __agent_start_monitoring(chan, p, 1);
2319 AST_LIST_UNLOCK(&agents);
2324 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);
2329 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");
2332 if (exitifnoagentid)
2338 /*! \brief Part of PBX channel interface */
2339 static int agent_devicestate(const char *data)
2341 struct agent_pvt *p;
2343 ast_group_t groupmatch;
2345 int res = AST_DEVICE_INVALID;
2348 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
2349 groupmatch = (1 << groupoff);
2350 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
2351 groupmatch = (1 << groupoff);
2355 /* Check actual logged in agents first */
2356 AST_LIST_LOCK(&agents);
2357 AST_LIST_TRAVERSE(&agents, p, list) {
2358 ast_mutex_lock(&p->lock);
2359 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2361 if (res != AST_DEVICE_INUSE)
2362 res = AST_DEVICE_BUSY;
2364 if (res == AST_DEVICE_BUSY)
2365 res = AST_DEVICE_INUSE;
2367 if (res == AST_DEVICE_INVALID)
2368 res = AST_DEVICE_UNKNOWN;
2369 } else if (res == AST_DEVICE_INVALID)
2370 res = AST_DEVICE_UNAVAILABLE;
2372 if (!strcmp(data, p->agent)) {
2373 ast_mutex_unlock(&p->lock);
2377 ast_mutex_unlock(&p->lock);
2379 AST_LIST_UNLOCK(&agents);
2384 * \note This function expects the agent list to be locked
2386 static struct agent_pvt *find_agent(char *agentid)
2388 struct agent_pvt *cur;
2390 AST_LIST_TRAVERSE(&agents, cur, list) {
2391 if (!strcmp(cur->agent, agentid))
2398 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2401 AST_DECLARE_APP_ARGS(args,
2402 AST_APP_ARG(agentid);
2406 struct agent_pvt *agent;
2410 if (ast_strlen_zero(data)) {
2411 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2415 parse = ast_strdupa(data);
2417 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2419 args.item = "status";
2421 AST_LIST_LOCK(&agents);
2423 if (!(agent = find_agent(args.agentid))) {
2424 AST_LIST_UNLOCK(&agents);
2425 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2429 if (!strcasecmp(args.item, "status")) {
2430 char *status = "LOGGEDOUT";
2432 status = "LOGGEDIN";
2434 ast_copy_string(buf, status, len);
2435 } else if (!strcasecmp(args.item, "password"))
2436 ast_copy_string(buf, agent->password, len);
2437 else if (!strcasecmp(args.item, "name"))
2438 ast_copy_string(buf, agent->name, len);
2439 else if (!strcasecmp(args.item, "mohclass"))
2440 ast_copy_string(buf, agent->moh, len);
2441 else if (!strcasecmp(args.item, "channel")) {
2443 ast_channel_lock(agent->chan);
2444 ast_copy_string(buf, ast_channel_name(agent->chan), len);
2445 ast_channel_unlock(agent->chan);
2446 tmp = strrchr(buf, '-');
2450 } else if (!strcasecmp(args.item, "fullchannel")) {
2452 ast_channel_lock(agent->chan);
2453 ast_copy_string(buf, ast_channel_name(agent->chan), len);
2454 ast_channel_unlock(agent->chan);
2456 } else if (!strcasecmp(args.item, "exten")) {
2460 AST_LIST_UNLOCK(&agents);
2465 static struct ast_custom_function agent_function = {
2467 .read = function_agent,
2472 * \brief Callback used to generate the agents tree.
2473 * \param[in] search The search pattern tree.
2474 * \retval NULL on error.
2475 * \retval non-NULL The generated tree.
2477 static int agents_data_provider_get(const struct ast_data_search *search,
2478 struct ast_data *data_root)
2480 struct agent_pvt *p;
2481 struct ast_data *data_agent, *data_channel, *data_talkingto;
2483 AST_LIST_LOCK(&agents);
2484 AST_LIST_TRAVERSE(&agents, p, list) {
2485 struct ast_channel *owner;
2487 data_agent = ast_data_add_node(data_root, "agent");
2492 ast_mutex_lock(&p->lock);
2493 owner = agent_lock_owner(p);
2495 if (!(p->pending)) {
2496 ast_data_add_str(data_agent, "id", p->agent);
2497 ast_data_add_structure(agent_pvt, data_agent, p);
2499 ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
2501 data_channel = ast_data_add_node(data_agent, "loggedon");
2502 if (!data_channel) {
2503 ast_mutex_unlock(&p->lock);
2504 ast_data_remove_node(data_root, data_agent);
2506 ast_channel_unlock(owner);
2507 owner = ast_channel_unref(owner);
2511 ast_channel_data_add_structure(data_channel, p->chan, 0);
2512 if (owner && ast_bridged_channel(owner)) {
2513 data_talkingto = ast_data_add_node(data_agent, "talkingto");
2514 if (!data_talkingto) {
2515 ast_mutex_unlock(&p->lock);
2516 ast_data_remove_node(data_root, data_agent);
2518 ast_channel_unlock(owner);
2519 owner = ast_channel_unref(owner);
2523 ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
2526 ast_data_add_node(data_agent, "talkingto");
2527 ast_data_add_node(data_agent, "loggedon");
2529 ast_data_add_str(data_agent, "musiconhold", p->moh);
2533 ast_channel_unlock(owner);
2534 owner = ast_channel_unref(owner);
2537 ast_mutex_unlock(&p->lock);
2539 /* if this agent doesn't match remove the added agent. */
2540 if (!ast_data_search_match(search, data_agent)) {
2541 ast_data_remove_node(data_root, data_agent);
2544 AST_LIST_UNLOCK(&agents);
2549 static const struct ast_data_handler agents_data_provider = {
2550 .version = AST_DATA_HANDLER_VERSION,
2551 .get = agents_data_provider_get
2554 static const struct ast_data_entry agents_data_providers[] = {
2555 AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
2559 * \brief Initialize the Agents module.
2560 * This function is being called by Asterisk when loading the module.
2561 * Among other things it registers applications, cli commands and reads the cofiguration file.
2563 * \returns int Always 0.
2565 static int load_module(void)
2567 if (!(agent_tech.capabilities = ast_format_cap_alloc())) {
2568 ast_log(LOG_ERROR, "ast_format_cap_alloc_nolock fail.\n");
2569 return AST_MODULE_LOAD_FAILURE;
2571 ast_format_cap_add_all(agent_tech.capabilities);
2572 /* Make sure we can register our agent channel type */
2573 if (ast_channel_register(&agent_tech)) {
2574 agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2575 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2576 return AST_MODULE_LOAD_FAILURE;
2578 /* Read in the config */
2579 if (!read_agent_config(0)) {
2580 agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2581 return AST_MODULE_LOAD_DECLINE;
2583 /* Dialplan applications */
2584 ast_register_application_xml(app, login_exec);
2585 ast_register_application_xml(app3, agentmonitoroutgoing_exec);
2588 ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
2590 /* Manager commands */
2591 ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
2592 ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
2595 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
2597 /* Dialplan Functions */
2598 ast_custom_function_register(&agent_function);
2600 return AST_MODULE_LOAD_SUCCESS;
2603 static int reload(void)
2605 return read_agent_config(1);
2608 static int unload_module(void)
2610 struct agent_pvt *p;
2611 /* First, take us out of the channel loop */
2612 ast_channel_unregister(&agent_tech);
2613 /* Unregister dialplan functions */
2614 ast_custom_function_unregister(&agent_function);
2615 /* Unregister CLI commands */
2616 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
2617 /* Unregister dialplan applications */
2618 ast_unregister_application(app);
2619 ast_unregister_application(app3);
2620 /* Unregister manager command */
2621 ast_manager_unregister("Agents");
2622 ast_manager_unregister("AgentLogoff");
2623 /* Unregister the data tree */
2624 ast_data_unregister(NULL);
2625 /* Unregister channel */
2626 AST_LIST_LOCK(&agents);
2627 /* Hangup all interfaces if they have an owner */
2628 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2630 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2633 AST_LIST_UNLOCK(&agents);
2635 agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2639 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Agent Proxy Channel",
2640 .load = load_module,
2641 .unload = unload_module,
2643 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2644 .nonoptreq = "res_monitor,chan_local",