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, AST_DEVSTATE_CACHABLE, "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);
788 ast_mutex_lock(&p->lock);
789 if (p->chan && !ast_check_hangup(p->chan)) {
790 ast_channel_unlock(ast);
791 ast_channel_lock(p->chan);
792 res = ast_channel_tech(p->chan)->indicate
793 ? ast_channel_tech(p->chan)->indicate(p->chan, condition, data, datalen)
795 ast_channel_unlock(p->chan);
796 ast_mutex_unlock(&p->lock);
797 ast_channel_lock(ast);
799 ast_mutex_unlock(&p->lock);
805 static int agent_digit_begin(struct ast_channel *ast, char digit)
807 struct agent_pvt *p = ast_channel_tech_pvt(ast);
808 ast_mutex_lock(&p->lock);
810 ast_senddigit_begin(p->chan, digit);
812 ast_mutex_unlock(&p->lock);
816 static int agent_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
818 struct agent_pvt *p = ast_channel_tech_pvt(ast);
819 ast_mutex_lock(&p->lock);
821 ast_senddigit_end(p->chan, digit, duration);
823 ast_mutex_unlock(&p->lock);
827 static int agent_call(struct ast_channel *ast, const char *dest, int timeout)
829 struct agent_pvt *p = ast_channel_tech_pvt(ast);
832 struct ast_channel *chan;
834 ast_mutex_lock(&p->lock);
838 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
839 ast_mutex_unlock(&p->lock);
840 ast_setstate(ast, AST_STATE_DIALING);
845 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
846 ast_mutex_unlock(&p->lock);
849 ast_verb(3, "agent_call, call to agent '%s' call on '%s'\n", p->agent, ast_channel_name(p->chan));
850 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(p->chan));
853 ast_mutex_unlock(&p->lock);
855 res = ast_streamfile(chan, beep, ast_channel_language(chan));
856 ast_debug(3, "Played beep, result '%d'\n", res);
858 res = ast_waitstream(chan, "");
859 ast_debug(3, "Waited for stream, result '%d'\n", res);
862 ast_mutex_lock(&p->lock);
864 /* chan went away while we were streaming, this shouldn't be possible */
869 struct ast_format tmpfmt;
870 res = ast_set_read_format_from_cap(p->chan, ast_channel_nativeformats(p->chan));
871 ast_debug(3, "Set read format, result '%d'\n", res);
873 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
877 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
881 struct ast_format tmpfmt;
882 res = ast_set_write_format_from_cap(p->chan, ast_channel_nativeformats(p->chan));
883 ast_debug(3, "Set write format, result '%d'\n", res);
885 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
888 /* Call is immediately up, or might need ack */
890 newstate = AST_STATE_RINGING;
892 newstate = AST_STATE_UP;
893 if (recordagentcalls)
894 agent_start_monitoring(ast, 0);
900 ast_mutex_unlock(&p->lock);
902 ast_setstate(ast, newstate);
906 /*! \brief return the channel or base channel if one exists. This function assumes the channel it is called on is already locked */
907 struct ast_channel* agent_get_base_channel(struct ast_channel *chan)
909 struct agent_pvt *p = NULL;
910 struct ast_channel *base = chan;
912 /* chan is locked by the calling function */
913 if (!chan || !ast_channel_tech_pvt(chan)) {
914 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);
917 p = ast_channel_tech_pvt(chan);
923 int agent_set_base_channel(struct ast_channel *chan, struct ast_channel *base)
925 struct agent_pvt *p = NULL;
927 if (!chan || !base) {
928 ast_log(LOG_ERROR, "whoa, you need a channel (0x%ld) and a base channel (0x%ld) for setting.\n", (long)chan, (long)base);
931 p = ast_channel_tech_pvt(chan);
933 ast_log(LOG_ERROR, "whoa, channel %s is missing his tech_pvt structure!!.\n", ast_channel_name(chan));
940 static int agent_hangup(struct ast_channel *ast)
942 struct agent_pvt *p = ast_channel_tech_pvt(ast);
943 struct ast_channel *indicate_chan = NULL;
944 char *tmp_moh; /* moh buffer for indicating after unlocking p */
947 AST_LIST_LOCK(&agents);
948 AST_LIST_REMOVE(&agents, p, list);
949 AST_LIST_UNLOCK(&agents);
952 ast_mutex_lock(&p->lock);
954 ast_channel_tech_pvt_set(ast, NULL);
955 p->app_sleep_cond = 1;
958 /* Release ownership of the agent to other threads (presumably running the login app). */
959 p->app_lock_flag = 0;
960 ast_cond_signal(&p->app_complete_cond);
962 /* if they really are hung up then set start to 0 so the test
963 * later if we're called on an already downed channel
964 * doesn't cause an agent to be logged out like when
965 * agent_request() is followed immediately by agent_hangup()
966 * as in apps/app_chanisavail.c:chanavail_exec()
969 ast_debug(1, "Hangup called for state %s\n", ast_state2str(ast_channel_state(ast)));
970 if (p->start && (ast_channel_state(ast) != AST_STATE_UP)) {
975 ast_channel_internal_bridged_channel_set(p->chan, NULL);
976 /* If they're dead, go ahead and hang up on the agent now */
978 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
979 } else if (p->loginstart) {
980 indicate_chan = ast_channel_ref(p->chan);
981 tmp_moh = ast_strdupa(p->moh);
984 ast_mutex_unlock(&p->lock);
987 ast_indicate_data(indicate_chan, AST_CONTROL_HOLD,
989 !ast_strlen_zero(tmp_moh) ? strlen(tmp_moh) + 1 : 0);
990 indicate_chan = ast_channel_unref(indicate_chan);
993 /* Only register a device state change if the agent is still logged in */
994 if (!p->loginstart) {
995 p->logincallerid[0] = '\0';
997 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
1000 if (p->abouttograb) {
1001 /* Let the "about to grab" thread know this isn't valid anymore, and let it
1004 } else if (p->dead) {
1005 ast_mutex_destroy(&p->lock);
1006 ast_cond_destroy(&p->app_complete_cond);
1007 ast_cond_destroy(&p->login_wait_cond);
1011 /* Not dead -- check availability now */
1012 ast_mutex_lock(&p->lock);
1013 /* Store last disconnect time */
1014 p->lastdisc = ast_tvadd(ast_tvnow(), ast_samp2tv(p->wrapuptime, 1000));
1015 ast_mutex_unlock(&p->lock);
1021 static int agent_cont_sleep( void *data )
1023 struct agent_pvt *p;
1026 p = (struct agent_pvt *)data;
1028 ast_mutex_lock(&p->lock);
1029 res = p->app_sleep_cond;
1030 if (p->lastdisc.tv_sec) {
1031 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0)
1034 ast_mutex_unlock(&p->lock);
1037 ast_debug(5, "agent_cont_sleep() returning %d\n", res );
1042 static int agent_ack_sleep(void *data)
1044 struct agent_pvt *p;
1047 struct ast_frame *f;
1048 struct timeval start = ast_tvnow();
1051 /* Wait a second and look for something */
1053 p = (struct agent_pvt *) data;
1057 while ((ms = ast_remaining_ms(start, to))) {
1058 ms = ast_waitfor(p->chan, ms);
1065 f = ast_read(p->chan);
1068 if (f->frametype == AST_FRAME_DTMF)
1069 res = f->subclass.integer;
1073 ast_mutex_lock(&p->lock);
1074 if (!p->app_sleep_cond) {
1075 ast_mutex_unlock(&p->lock);
1077 } else if (res == p->acceptdtmf) {
1078 ast_mutex_unlock(&p->lock);
1081 ast_mutex_unlock(&p->lock);
1087 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
1089 struct agent_pvt *p = ast_channel_tech_pvt(bridge);
1090 struct ast_channel *ret = NULL;
1093 if (chan == p->chan)
1094 ret = ast_channel_internal_bridged_channel(bridge);
1095 else if (chan == ast_channel_internal_bridged_channel(bridge))
1099 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>");
1103 /*! \brief Create new agent channel */
1104 static struct ast_channel *agent_new(struct agent_pvt *p, int state, const char *linkedid, struct ast_callid *callid)
1106 struct ast_channel *tmp;
1109 ast_log(LOG_WARNING, "No channel? :(\n");
1114 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);
1116 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);
1118 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
1123 ast_channel_callid_set(tmp, callid);
1126 ast_channel_tech_set(tmp, &agent_tech);
1128 ast_format_cap_copy(ast_channel_nativeformats(tmp), ast_channel_nativeformats(p->chan));
1129 ast_format_copy(ast_channel_writeformat(tmp), ast_channel_writeformat(p->chan));
1130 ast_format_copy(ast_channel_rawwriteformat(tmp), ast_channel_writeformat(p->chan));
1131 ast_format_copy(ast_channel_readformat(tmp), ast_channel_readformat(p->chan));
1132 ast_format_copy(ast_channel_rawreadformat(tmp), ast_channel_readformat(p->chan));
1133 ast_channel_language_set(tmp, ast_channel_language(p->chan));
1134 ast_channel_context_set(tmp, ast_channel_context(p->chan));
1135 ast_channel_exten_set(tmp, ast_channel_exten(p->chan));
1136 /* XXX Is this really all we copy form the originating channel?? */
1138 ast_format_set(ast_channel_writeformat(tmp), AST_FORMAT_SLINEAR, 0);
1139 ast_format_set(ast_channel_rawwriteformat(tmp), AST_FORMAT_SLINEAR, 0);
1140 ast_format_set(ast_channel_readformat(tmp), AST_FORMAT_SLINEAR, 0);
1141 ast_format_set(ast_channel_rawreadformat(tmp), AST_FORMAT_SLINEAR, 0);
1142 ast_format_cap_add(ast_channel_nativeformats(tmp), ast_channel_writeformat(tmp));
1144 /* Safe, agentlock already held */
1145 ast_channel_tech_pvt_set(tmp, p);
1147 ast_channel_priority_set(tmp, 1);
1153 * Read configuration data. The file named agents.conf.
1155 * \returns Always 0, or so it seems.
1157 static int read_agent_config(int reload)
1159 struct ast_config *cfg;
1160 struct ast_config *ucfg;
1161 struct ast_variable *v;
1162 struct agent_pvt *p;
1163 const char *catname;
1164 const char *hasagent;
1166 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1173 cfg = ast_config_load(config, config_flags);
1175 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
1177 } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1179 } else if (cfg == CONFIG_STATUS_FILEINVALID) {
1180 ast_log(LOG_ERROR, "%s contains a parsing error. Aborting\n", config);
1183 if ((ucfg = ast_config_load("users.conf", config_flags))) {
1184 if (ucfg == CONFIG_STATUS_FILEUNCHANGED) {
1186 } else if (ucfg == CONFIG_STATUS_FILEINVALID) {
1187 ast_log(LOG_ERROR, "users.conf contains a parsing error. Aborting\n");
1192 AST_LIST_LOCK(&agents);
1193 AST_LIST_TRAVERSE(&agents, p, list) {
1196 strcpy(moh, "default");
1197 /* set the default recording values */
1198 recordagentcalls = 0;
1199 strcpy(recordformat, "wav");
1200 strcpy(recordformatext, "wav");
1201 urlprefix[0] = '\0';
1202 savecallsin[0] = '\0';
1204 /* Read in the [agents] section */
1205 v = ast_variable_browse(cfg, "agents");
1207 /* Create the interface list */
1208 if (!strcasecmp(v->name, "agent")) {
1209 add_agent(v->value, 0);
1210 } else if (!strcasecmp(v->name, "group")) {
1211 group = ast_get_group(v->value);
1212 } else if (!strcasecmp(v->name, "autologoff")) {
1213 autologoff = atoi(v->value);
1216 } else if (!strcasecmp(v->name, "ackcall")) {
1217 if (ast_true(v->value) || !strcasecmp(v->value, "always")) {
1220 } else if (!strcasecmp(v->name, "endcall")) {
1221 endcall = ast_true(v->value);
1222 } else if (!strcasecmp(v->name, "acceptdtmf")) {
1223 acceptdtmf = *(v->value);
1224 ast_log(LOG_NOTICE, "Set acceptdtmf to %c\n", acceptdtmf);
1225 } else if (!strcasecmp(v->name, "enddtmf")) {
1226 enddtmf = *(v->value);
1227 } else if (!strcasecmp(v->name, "wrapuptime")) {
1228 wrapuptime = atoi(v->value);
1231 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1232 maxlogintries = atoi(v->value);
1233 if (maxlogintries < 0)
1235 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1236 strcpy(agentgoodbye,v->value);
1237 } else if (!strcasecmp(v->name, "musiconhold")) {
1238 ast_copy_string(moh, v->value, sizeof(moh));
1239 } else if (!strcasecmp(v->name, "updatecdr")) {
1240 if (ast_true(v->value))
1244 } else if (!strcasecmp(v->name, "autologoffunavail")) {
1245 if (ast_true(v->value))
1246 autologoffunavail = 1;
1248 autologoffunavail = 0;
1249 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1250 recordagentcalls = ast_true(v->value);
1251 } else if (!strcasecmp(v->name, "recordformat")) {
1252 ast_copy_string(recordformat, v->value, sizeof(recordformat));
1253 if (!strcasecmp(v->value, "wav49"))
1254 strcpy(recordformatext, "WAV");
1256 ast_copy_string(recordformatext, v->value, sizeof(recordformatext));
1257 } else if (!strcasecmp(v->name, "urlprefix")) {
1258 ast_copy_string(urlprefix, v->value, sizeof(urlprefix));
1259 if (urlprefix[strlen(urlprefix) - 1] != '/')
1260 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1261 } else if (!strcasecmp(v->name, "savecallsin")) {
1262 if (v->value[0] == '/')
1263 ast_copy_string(savecallsin, v->value, sizeof(savecallsin));
1265 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1266 if (savecallsin[strlen(savecallsin) - 1] != '/')
1267 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1268 } else if (!strcasecmp(v->name, "custom_beep")) {
1269 ast_copy_string(beep, v->value, sizeof(beep));
1274 genhasagent = ast_true(ast_variable_retrieve(ucfg, "general", "hasagent"));
1275 catname = ast_category_browse(ucfg, NULL);
1277 if (strcasecmp(catname, "general")) {
1278 hasagent = ast_variable_retrieve(ucfg, catname, "hasagent");
1279 if (ast_true(hasagent) || (!hasagent && genhasagent)) {
1281 const char *fullname = ast_variable_retrieve(ucfg, catname, "fullname");
1282 const char *secret = ast_variable_retrieve(ucfg, catname, "secret");
1287 snprintf(tmp, sizeof(tmp), "%s,%s,%s", catname, secret,fullname);
1291 catname = ast_category_browse(ucfg, catname);
1293 ast_config_destroy(ucfg);
1295 AST_LIST_TRAVERSE_SAFE_BEGIN(&agents, p, list) {
1297 AST_LIST_REMOVE_CURRENT(list);
1298 /* Destroy if appropriate */
1301 ast_mutex_destroy(&p->lock);
1302 ast_cond_destroy(&p->app_complete_cond);
1303 ast_cond_destroy(&p->login_wait_cond);
1306 /* Cause them to hang up */
1307 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1312 AST_LIST_TRAVERSE_SAFE_END;
1313 AST_LIST_UNLOCK(&agents);
1314 ast_config_destroy(cfg);
1318 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1320 struct ast_channel *chan=NULL, *parent=NULL;
1321 struct agent_pvt *p;
1324 ast_debug(1, "Checking availability of '%s'\n", newlyavailable->agent);
1326 AST_LIST_LOCK(&agents);
1327 AST_LIST_TRAVERSE(&agents, p, list) {
1328 if (p == newlyavailable) {
1331 ast_mutex_lock(&p->lock);
1332 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1333 ast_debug(1, "Call '%s' looks like a winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1334 /* We found a pending call, time to merge */
1335 chan = agent_new(newlyavailable, AST_STATE_DOWN, p->owner ? ast_channel_linkedid(p->owner) : NULL, NULL);
1338 ast_mutex_unlock(&p->lock);
1341 ast_mutex_unlock(&p->lock);
1344 AST_LIST_UNLOCK(&agents);
1345 if (parent && chan) {
1346 if (newlyavailable->ackcall) {
1347 /* Don't do beep here */
1350 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1351 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1352 ast_debug(3, "Played beep, result '%d'\n", res);
1354 res = ast_waitstream(newlyavailable->chan, "");
1355 ast_debug(1, "Waited for stream, result '%d'\n", res);
1359 /* Note -- parent may have disappeared */
1360 if (p->abouttograb) {
1361 newlyavailable->acknowledged = 1;
1362 /* Safe -- agent lock already held */
1363 ast_setstate(parent, AST_STATE_UP);
1364 ast_setstate(chan, AST_STATE_UP);
1365 ast_channel_context_set(parent, ast_channel_context(chan));
1366 ast_channel_masquerade(parent, chan);
1370 ast_debug(1, "Sneaky, parent disappeared in the mean time...\n");
1371 agent_cleanup(newlyavailable);
1374 ast_debug(1, "Ugh... Agent hung up at exactly the wrong time\n");
1375 agent_cleanup(newlyavailable);
1381 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1383 struct agent_pvt *p;
1386 ast_debug(1, "Checking beep availability of '%s'\n", newlyavailable->agent);
1388 AST_LIST_LOCK(&agents);
1389 AST_LIST_TRAVERSE(&agents, p, list) {
1390 if (p == newlyavailable) {
1393 ast_mutex_lock(&p->lock);
1394 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1395 ast_debug(1, "Call '%s' looks like a would-be winner for agent '%s'\n", ast_channel_name(p->owner), newlyavailable->agent);
1396 ast_mutex_unlock(&p->lock);
1399 ast_mutex_unlock(&p->lock);
1402 AST_LIST_UNLOCK(&agents);
1404 ast_mutex_unlock(&newlyavailable->lock);
1405 ast_debug(3, "Playing beep, lang '%s'\n", ast_channel_language(newlyavailable->chan));
1406 res = ast_streamfile(newlyavailable->chan, beep, ast_channel_language(newlyavailable->chan));
1407 ast_debug(1, "Played beep, result '%d'\n", res);
1409 res = ast_waitstream(newlyavailable->chan, "");
1410 ast_debug(1, "Waited for stream, result '%d'\n", res);
1412 ast_mutex_lock(&newlyavailable->lock);
1417 /*! \brief Part of the Asterisk PBX interface */
1418 static struct ast_channel *agent_request(const char *type, struct ast_format_cap *cap, const struct ast_channel* requestor, const char *data, int *cause)
1420 struct agent_pvt *p;
1421 struct ast_channel *chan = NULL;
1423 ast_group_t groupmatch;
1428 struct ast_callid *callid = ast_read_threadstorage_callid();
1431 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1432 groupmatch = (1 << groupoff);
1433 } else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
1434 groupmatch = (1 << groupoff);
1439 /* Check actual logged in agents first */
1440 AST_LIST_LOCK(&agents);
1441 AST_LIST_TRAVERSE(&agents, p, list) {
1442 ast_mutex_lock(&p->lock);
1443 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1448 if (!p->lastdisc.tv_sec || (now.tv_sec >= p->lastdisc.tv_sec)) {
1449 p->lastdisc = ast_tv(0, 0);
1450 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1451 if (!p->owner && p->chan) {
1453 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
1456 ast_mutex_unlock(&p->lock);
1461 ast_mutex_unlock(&p->lock);
1464 if (!chan && waitforagent) {
1465 /* No agent available -- but we're requesting to wait for one.
1466 Allocate a place holder */
1468 ast_debug(1, "Creating place holder for '%s'\n", s);
1469 p = add_agent(data, 1);
1470 p->group = groupmatch;
1471 chan = agent_new(p, AST_STATE_DOWN, requestor ? ast_channel_linkedid(requestor) : NULL, callid);
1473 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1475 ast_debug(1, "Not creating place holder for '%s' since nobody logged in\n", s);
1478 *cause = hasagent ? AST_CAUSE_BUSY : AST_CAUSE_UNREGISTERED;
1479 AST_LIST_UNLOCK(&agents);
1482 callid = ast_callid_unref(callid);
1486 ast_mutex_lock(&p->lock);
1488 ast_mutex_unlock(&p->lock);
1493 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1494 *cause = AST_CAUSE_UNREGISTERED;
1495 ast_mutex_unlock(&p->lock);
1500 /* we need to take control of the channel from the login app
1502 p->app_sleep_cond = 0;
1503 p->app_lock_flag = 1;
1505 ast_queue_frame(p->chan, &ast_null_frame);
1506 ast_cond_wait(&p->login_wait_cond, &p->lock);
1509 ast_log(LOG_DEBUG, "Agent disconnected while we were connecting the call\n");
1510 p->app_sleep_cond = 1;
1511 p->app_lock_flag = 0;
1512 ast_cond_signal(&p->app_complete_cond);
1513 ast_mutex_unlock(&p->lock);
1514 *cause = AST_CAUSE_UNREGISTERED;
1519 ast_indicate(p->chan, AST_CONTROL_UNHOLD);
1520 ast_mutex_unlock(&p->lock);
1526 static force_inline int powerof(unsigned int d)
1537 * Lists agents and their status to the Manager API.
1538 * It is registered on load_module() and it gets called by the manager backend.
1539 * This function locks both the pvt and the channel that owns it for a while, but
1540 * does not keep these locks.
1544 * \sa action_agent_logoff(), load_module().
1546 static int action_agents(struct mansession *s, const struct message *m)
1548 const char *id = astman_get_header(m,"ActionID");
1549 char idText[256] = "";
1550 struct agent_pvt *p;
1551 char *username = NULL;
1552 char *loginChan = NULL;
1553 char *talkingto = NULL;
1554 char *talkingtoChan = NULL;
1555 char *status = NULL;
1556 struct ast_channel *bridge;
1558 if (!ast_strlen_zero(id))
1559 snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
1560 astman_send_ack(s, m, "Agents will follow");
1561 AST_LIST_LOCK(&agents);
1562 AST_LIST_TRAVERSE(&agents, p, list) {
1563 struct ast_channel *owner;
1564 ast_mutex_lock(&p->lock);
1565 owner = agent_lock_owner(p);
1568 AGENT_LOGGEDOFF - Agent isn't logged in
1569 AGENT_IDLE - Agent is logged in, and waiting for call
1570 AGENT_ONCALL - Agent is logged in, and on a call
1571 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1573 username = S_OR(p->name, "None");
1575 /* Set a default status. It 'should' get changed. */
1576 status = "AGENT_UNKNOWN";
1579 loginChan = ast_strdupa(ast_channel_name(p->chan));
1580 if (owner && ast_channel_internal_bridged_channel(owner)) {
1581 talkingto = S_COR(ast_channel_caller(p->chan)->id.number.valid,
1582 ast_channel_caller(p->chan)->id.number.str, "n/a");
1583 if ((bridge = ast_bridged_channel(owner))) {
1584 talkingtoChan = ast_strdupa(ast_channel_name(bridge));
1586 talkingtoChan = "n/a";
1588 status = "AGENT_ONCALL";
1591 talkingtoChan = "n/a";
1592 status = "AGENT_IDLE";
1597 talkingtoChan = "n/a";
1598 status = "AGENT_LOGGEDOFF";
1602 ast_channel_unlock(owner);
1603 owner = ast_channel_unref(owner);
1606 astman_append(s, "Event: Agents\r\n"
1610 "LoggedInChan: %s\r\n"
1611 "LoggedInTime: %d\r\n"
1613 "TalkingToChan: %s\r\n"
1616 p->agent, username, status, loginChan, (int)p->loginstart, talkingto, talkingtoChan, idText);
1617 ast_mutex_unlock(&p->lock);
1619 AST_LIST_UNLOCK(&agents);
1620 astman_append(s, "Event: AgentsComplete\r\n"
1626 static int agent_logoff(const char *agent, int soft)
1628 struct agent_pvt *p;
1629 int ret = -1; /* Return -1 if no agent if found */
1631 AST_LIST_LOCK(&agents);
1632 AST_LIST_TRAVERSE(&agents, p, list) {
1633 if (!strcasecmp(p->agent, agent)) {
1635 if (p->owner || p->chan) {
1637 struct ast_channel *owner;
1638 ast_mutex_lock(&p->lock);
1639 owner = agent_lock_owner(p);
1642 ast_softhangup(owner, AST_SOFTHANGUP_EXPLICIT);
1643 ast_channel_unlock(owner);
1644 owner = ast_channel_unref(owner);
1647 while (p->chan && ast_channel_trylock(p->chan)) {
1648 DEADLOCK_AVOIDANCE(&p->lock);
1651 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1652 ast_channel_unlock(p->chan);
1655 ast_mutex_unlock(&p->lock);
1662 AST_LIST_UNLOCK(&agents);
1667 static char *agent_logoff_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1674 e->command = "agent logoff";
1676 "Usage: agent logoff <channel> [soft]\n"
1677 " Sets an agent as no longer logged in.\n"
1678 " If 'soft' is specified, do not hangup existing calls.\n";
1681 return complete_agent_logoff_cmd(a->line, a->word, a->pos, a->n);
1684 if (a->argc < 3 || a->argc > 4)
1685 return CLI_SHOWUSAGE;
1686 if (a->argc == 4 && strcasecmp(a->argv[3], "soft"))
1687 return CLI_SHOWUSAGE;
1689 agent = a->argv[2] + 6;
1690 ret = agent_logoff(agent, a->argc == 4);
1692 ast_cli(a->fd, "Logging out %s\n", agent);
1698 * Sets an agent as no longer logged in in the Manager API.
1699 * It is registered on load_module() and it gets called by the manager backend.
1703 * \sa action_agents(), load_module().
1705 static int action_agent_logoff(struct mansession *s, const struct message *m)
1707 const char *agent = astman_get_header(m, "Agent");
1708 const char *soft_s = astman_get_header(m, "Soft"); /* "true" is don't hangup */
1710 int ret; /* return value of agent_logoff */
1712 if (ast_strlen_zero(agent)) {
1713 astman_send_error(s, m, "No agent specified");
1717 soft = ast_true(soft_s) ? 1 : 0;
1718 ret = agent_logoff(agent, soft);
1720 astman_send_ack(s, m, "Agent logged out");
1722 astman_send_error(s, m, "No such agent");
1727 static char *complete_agent_logoff_cmd(const char *line, const char *word, int pos, int state)
1732 struct agent_pvt *p;
1733 char name[AST_MAX_AGENT];
1734 int which = 0, len = strlen(word);
1736 AST_LIST_LOCK(&agents);
1737 AST_LIST_TRAVERSE(&agents, p, list) {
1738 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1739 if (!strncasecmp(word, name, len) && p->loginstart && ++which > state) {
1740 ret = ast_strdup(name);
1744 AST_LIST_UNLOCK(&agents);
1745 } else if (pos == 3 && state == 0)
1746 return ast_strdup("soft");
1752 * Show agents in cli.
1754 static char *agents_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1756 struct agent_pvt *p;
1757 char username[AST_MAX_BUF];
1758 char location[AST_MAX_BUF] = "";
1759 char talkingto[AST_MAX_BUF] = "";
1760 char music[AST_MAX_BUF];
1761 int count_agents = 0; /*!< Number of agents configured */
1762 int online_agents = 0; /*!< Number of online agents */
1763 int offline_agents = 0; /*!< Number of offline agents */
1767 e->command = "agent show";
1769 "Usage: agent show\n"
1770 " Provides summary information on agents.\n";
1777 return CLI_SHOWUSAGE;
1779 AST_LIST_LOCK(&agents);
1780 AST_LIST_TRAVERSE(&agents, p, list) {
1781 struct ast_channel *owner;
1782 ast_mutex_lock(&p->lock);
1783 owner = agent_lock_owner(p);
1786 ast_cli(a->fd, "-- Pending call to group %d\n", powerof(p->group));
1788 ast_cli(a->fd, "-- Pending call to agent %s\n", p->agent);
1790 if (!ast_strlen_zero(p->name))
1791 snprintf(username, sizeof(username), "(%s) ", p->name);
1795 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1796 if (owner && ast_bridged_channel(owner)) {
1797 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1799 strcpy(talkingto, " is idle");
1803 strcpy(location, "not logged in");
1804 talkingto[0] = '\0';
1807 if (!ast_strlen_zero(p->moh))
1808 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1809 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent,
1810 username, location, talkingto, music);
1815 ast_channel_unlock(owner);
1816 owner = ast_channel_unref(owner);
1818 ast_mutex_unlock(&p->lock);
1820 AST_LIST_UNLOCK(&agents);
1821 if ( !count_agents )
1822 ast_cli(a->fd, "No Agents are configured in %s\n",config);
1824 ast_cli(a->fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1825 ast_cli(a->fd, "\n");
1831 static char *agents_show_online(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1833 struct agent_pvt *p;
1834 char username[AST_MAX_BUF];
1835 char location[AST_MAX_BUF] = "";
1836 char talkingto[AST_MAX_BUF] = "";
1837 char music[AST_MAX_BUF];
1838 int count_agents = 0; /* Number of agents configured */
1839 int online_agents = 0; /* Number of online agents */
1840 int agent_status = 0; /* 0 means offline, 1 means online */
1844 e->command = "agent show online";
1846 "Usage: agent show online\n"
1847 " Provides a list of all online agents.\n";
1854 return CLI_SHOWUSAGE;
1856 AST_LIST_LOCK(&agents);
1857 AST_LIST_TRAVERSE(&agents, p, list) {
1858 struct ast_channel *owner;
1860 agent_status = 0; /* reset it to offline */
1861 ast_mutex_lock(&p->lock);
1862 owner = agent_lock_owner(p);
1864 if (!ast_strlen_zero(p->name))
1865 snprintf(username, sizeof(username), "(%s) ", p->name);
1869 snprintf(location, sizeof(location), "logged in on %s", ast_channel_name(p->chan));
1870 if (p->owner && ast_bridged_channel(p->owner)) {
1871 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_channel_name(ast_bridged_channel(p->owner)));
1873 strcpy(talkingto, " is idle");
1880 ast_channel_unlock(owner);
1881 owner = ast_channel_unref(owner);
1884 if (!ast_strlen_zero(p->moh))
1885 snprintf(music, sizeof(music), " (musiconhold is '%s')", p->moh);
1887 ast_cli(a->fd, "%-12.12s %s%s%s%s\n", p->agent, username, location, talkingto, music);
1889 ast_mutex_unlock(&p->lock);
1891 AST_LIST_UNLOCK(&agents);
1893 ast_cli(a->fd, "No Agents are configured in %s\n", config);
1895 ast_cli(a->fd, "%d agents online\n", online_agents);
1896 ast_cli(a->fd, "\n");
1900 static const char agent_logoff_usage[] =
1901 "Usage: agent logoff <channel> [soft]\n"
1902 " Sets an agent as no longer logged in.\n"
1903 " If 'soft' is specified, do not hangup existing calls.\n";
1905 static struct ast_cli_entry cli_agents[] = {
1906 AST_CLI_DEFINE(agents_show, "Show status of agents"),
1907 AST_CLI_DEFINE(agents_show_online, "Show all online agents"),
1908 AST_CLI_DEFINE(agent_logoff_cmd, "Sets an agent offline"),
1912 * Called by the AgentLogin application (from the dial plan).
1914 * \brief Log in agent application.
1919 * \sa agentmonitoroutgoing_exec(), load_module().
1921 static int login_exec(struct ast_channel *chan, const char *data)
1925 int max_login_tries = maxlogintries;
1926 struct agent_pvt *p;
1927 struct ast_module_user *u;
1928 char user[AST_MAX_AGENT] = "";
1929 char pass[AST_MAX_AGENT];
1930 char agent[AST_MAX_AGENT] = "";
1931 char xpass[AST_MAX_AGENT] = "";
1934 AST_DECLARE_APP_ARGS(args,
1935 AST_APP_ARG(agent_id);
1936 AST_APP_ARG(options);
1937 AST_APP_ARG(extension);
1939 const char *tmpoptions = NULL;
1940 int play_announcement = 1;
1941 char agent_goodbye[AST_MAX_FILENAME_LEN];
1942 int update_cdr = updatecdr;
1943 char *filename = "agent-loginok";
1945 u = ast_module_user_add(chan);
1947 parse = ast_strdupa(data);
1949 AST_STANDARD_APP_ARGS(args, parse);
1951 ast_copy_string(agent_goodbye, agentgoodbye, sizeof(agent_goodbye));
1953 ast_channel_lock(chan);
1954 /* Set Channel Specific Login Overrides */
1955 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1956 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1957 if (max_login_tries < 0)
1958 max_login_tries = 0;
1959 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1960 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));
1962 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1963 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1967 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1968 ast_verb(3, "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,ast_channel_name(chan));
1970 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1971 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1972 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1973 ast_verb(3, "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,ast_channel_name(chan));
1975 ast_channel_unlock(chan);
1976 /* End Channel Specific Login Overrides */
1978 if (!ast_strlen_zero(args.options)) {
1979 if (strchr(args.options, 's')) {
1980 play_announcement = 0;
1984 if (ast_channel_state(chan) != AST_STATE_UP)
1985 res = ast_answer(chan);
1987 if (!ast_strlen_zero(args.agent_id))
1988 ast_copy_string(user, args.agent_id, AST_MAX_AGENT);
1990 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1992 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1994 /* Check for password */
1995 AST_LIST_LOCK(&agents);
1996 AST_LIST_TRAVERSE(&agents, p, list) {
1997 if (!strcmp(p->agent, user) && !p->pending)
1998 ast_copy_string(xpass, p->password, sizeof(xpass));
2000 AST_LIST_UNLOCK(&agents);
2002 if (!ast_strlen_zero(xpass))
2003 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
2007 errmsg = "agent-incorrect";
2010 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
2013 /* Check again for accuracy */
2014 AST_LIST_LOCK(&agents);
2015 AST_LIST_TRAVERSE(&agents, p, list) {
2016 int unlock_channel = 1;
2017 ast_channel_lock(chan);
2018 ast_mutex_lock(&p->lock);
2019 if (!strcmp(p->agent, user) &&
2020 !strcmp(p->password, pass) && !p->pending) {
2022 /* Ensure we can't be gotten until we're done */
2023 p->lastdisc = ast_tvnow();
2024 p->lastdisc.tv_sec++;
2026 /* Set Channel Specific Agent Overrides */
2027 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2028 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
2033 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
2034 ast_verb(3, "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n", tmpoptions, p->ackcall, p->agent);
2035 ast_set_flag(p, AGENT_FLAG_ACKCALL);
2037 p->ackcall = ackcall;
2039 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
2040 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
2041 if (p->autologoff < 0)
2043 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
2044 ast_verb(3, "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n", tmpoptions, p->autologoff, p->agent);
2045 ast_set_flag(p, AGENT_FLAG_AUTOLOGOFF);
2047 p->autologoff = autologoff;
2049 if (!ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
2050 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
2051 if (p->wrapuptime < 0)
2053 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
2054 ast_verb(3, "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n", tmpoptions, p->wrapuptime, p->agent);
2055 ast_set_flag(p, AGENT_FLAG_WRAPUPTIME);
2057 p->wrapuptime = wrapuptime;
2059 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTACCEPTDTMF");
2060 if (!ast_strlen_zero(tmpoptions)) {
2061 p->acceptdtmf = *tmpoptions;
2062 ast_verb(3, "Saw variable AGENTACCEPTDTMF=%s, setting acceptdtmf to: %c for Agent '%s'.\n", tmpoptions, p->acceptdtmf, p->agent);
2063 ast_set_flag(p, AGENT_FLAG_ACCEPTDTMF);
2065 tmpoptions = pbx_builtin_getvar_helper(chan, "AGENTENDDTMF");
2066 if (!ast_strlen_zero(tmpoptions)) {
2067 p->enddtmf = *tmpoptions;
2068 ast_verb(3, "Saw variable AGENTENDDTMF=%s, setting enddtmf to: %c for Agent '%s'.\n", tmpoptions, p->enddtmf, p->agent);
2069 ast_set_flag(p, AGENT_FLAG_ENDDTMF);
2071 ast_channel_unlock(chan);
2073 /* End Channel Specific Agent Overrides */
2076 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
2078 p->logincallerid[0] = '\0';
2079 p->acknowledged = 0;
2081 ast_mutex_unlock(&p->lock);
2082 AST_LIST_UNLOCK(&agents);
2083 if( !res && play_announcement==1 )
2084 res = ast_streamfile(chan, filename, ast_channel_language(chan));
2086 ast_waitstream(chan, "");
2087 AST_LIST_LOCK(&agents);
2088 ast_mutex_lock(&p->lock);
2090 struct ast_format tmpfmt;
2091 res = ast_set_read_format_from_cap(chan, ast_channel_nativeformats(chan));
2093 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(&tmpfmt));
2097 struct ast_format tmpfmt;
2098 res = ast_set_write_format_from_cap(chan, ast_channel_nativeformats(chan));
2100 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(&tmpfmt));
2103 /* Check once more just in case */
2107 ast_indicate_data(chan, AST_CONTROL_HOLD,
2109 !ast_strlen_zero(p->moh) ? strlen(p->moh) + 1 : 0);
2110 if (p->loginstart == 0)
2111 time(&p->loginstart);
2113 <managerEventInstance>
2114 <synopsis>Raised when an Agent has logged in.</synopsis>
2116 <parameter name="Agent">
2117 <para>The name of the agent.</para>
2121 <ref type="application">AgentLogin</ref>
2122 <ref type="managerEvent">Agentlogoff</ref>
2124 </managerEventInstance>
2126 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
2130 p->agent, ast_channel_name(chan), ast_channel_uniqueid(chan));
2131 if (update_cdr && ast_channel_cdr(chan))
2132 snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "Agent/%s", p->agent);
2133 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGIN", "%s", ast_channel_name(chan));
2134 ast_verb(2, "Agent '%s' logged in (format %s/%s)\n", p->agent,
2135 ast_getformatname(ast_channel_readformat(chan)), ast_getformatname(ast_channel_writeformat(chan)));
2136 /* Login this channel and wait for it to go away */
2141 check_availability(p, 0);
2143 ast_mutex_unlock(&p->lock);
2144 AST_LIST_UNLOCK(&agents);
2145 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
2147 ast_mutex_lock(&p->lock);
2148 if (p->deferlogoff && p->chan) {
2149 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
2152 if (p->chan != chan)
2154 ast_mutex_unlock(&p->lock);
2155 /* Yield here so other interested threads can kick in. */
2160 AST_LIST_LOCK(&agents);
2161 ast_mutex_lock(&p->lock);
2162 if (p->lastdisc.tv_sec) {
2163 if (ast_tvdiff_ms(ast_tvnow(), p->lastdisc) > 0) {
2164 ast_debug(1, "Wrapup time for %s expired!\n", p->agent);
2165 p->lastdisc = ast_tv(0, 0);
2166 ast_devstate_changed(AST_DEVICE_NOT_INUSE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
2170 check_availability(p, 0);
2174 ast_mutex_unlock(&p->lock);
2175 AST_LIST_UNLOCK(&agents);
2177 /* Synchronize channel ownership between call to agent and itself. */
2178 ast_mutex_lock(&p->lock);
2179 if (p->app_lock_flag == 1) {
2180 ast_cond_signal(&p->login_wait_cond);
2181 ast_cond_wait(&p->app_complete_cond, &p->lock);
2183 ast_mutex_unlock(&p->lock);
2185 res = agent_ack_sleep(p);
2187 res = ast_safe_sleep_conditional( chan, 1000, agent_cont_sleep, p );
2189 if (p->ackcall && (res == 1)) {
2190 AST_LIST_LOCK(&agents);
2191 ast_mutex_lock(&p->lock);
2192 check_availability(p, 0);
2193 ast_mutex_unlock(&p->lock);
2194 AST_LIST_UNLOCK(&agents);
2199 ast_mutex_lock(&p->lock);
2200 /* Log us off if appropriate */
2201 if (p->chan == chan) {
2205 /* Synchronize channel ownership between call to agent and itself. */
2206 if (p->app_lock_flag == 1) {
2207 ast_cond_signal(&p->login_wait_cond);
2208 ast_cond_wait(&p->app_complete_cond, &p->lock);
2211 if (res && p->owner)
2212 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
2214 p->acknowledged = 0;
2215 logintime = time(NULL) - p->loginstart;
2217 ast_mutex_unlock(&p->lock);
2219 <managerEventInstance>
2220 <synopsis>Raised when an Agent has logged off.</synopsis>
2222 <xi:include xpointer="xpointer(/docs/managerEvent[@name='Agentlogin']/managerEventInstance/syntax/parameter[@name='Agent'])" />
2225 <ref type="managerEvent">Agentlogin</ref>
2227 </managerEventInstance>
2229 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
2231 "Logintime: %ld\r\n"
2233 p->agent, logintime, ast_channel_uniqueid(chan));
2234 ast_queue_log("NONE", ast_channel_uniqueid(chan), agent, "AGENTLOGOFF", "%s|%ld", ast_channel_name(chan), logintime);
2235 ast_verb(2, "Agent '%s' logged out\n", p->agent);
2236 /* If there is no owner, go ahead and kill it now */
2237 ast_devstate_changed(AST_DEVICE_UNAVAILABLE, AST_DEVSTATE_CACHABLE, "Agent/%s", p->agent);
2238 if (p->dead && !p->owner) {
2239 ast_mutex_destroy(&p->lock);
2240 ast_cond_destroy(&p->app_complete_cond);
2241 ast_cond_destroy(&p->login_wait_cond);
2246 ast_mutex_unlock(&p->lock);
2251 ast_mutex_unlock(&p->lock);
2252 errmsg = "agent-alreadyon";
2257 ast_mutex_unlock(&p->lock);
2258 if (unlock_channel) {
2259 ast_channel_unlock(chan);
2263 AST_LIST_UNLOCK(&agents);
2265 if (!res && (max_login_tries==0 || tries < max_login_tries))
2266 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
2270 res = ast_safe_sleep(chan, 500);
2272 ast_module_user_remove(u);
2278 * \brief Called by the AgentMonitorOutgoing application (from the dial plan).
2283 * \sa login_exec(), load_module().
2285 static int agentmonitoroutgoing_exec(struct ast_channel *chan, const char *data)
2287 int exitifnoagentid = 0;
2289 int changeoutgoing = 0;
2291 char agent[AST_MAX_AGENT];
2294 if (strchr(data, 'd'))
2295 exitifnoagentid = 1;
2296 if (strchr(data, 'n'))
2298 if (strchr(data, 'c'))
2301 if (ast_channel_caller(chan)->id.number.valid
2302 && !ast_strlen_zero(ast_channel_caller(chan)->id.number.str)) {
2304 char agentvar[AST_MAX_BUF];
2305 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID,
2306 ast_channel_caller(chan)->id.number.str);
2307 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2308 struct agent_pvt *p;
2309 ast_copy_string(agent, tmp, sizeof(agent));
2310 AST_LIST_LOCK(&agents);
2311 AST_LIST_TRAVERSE(&agents, p, list) {
2312 if (!strcasecmp(p->agent, tmp)) {
2313 if (changeoutgoing) snprintf(ast_channel_cdr(chan)->channel, sizeof(ast_channel_cdr(chan)->channel), "Agent/%s", p->agent);
2314 __agent_start_monitoring(chan, p, 1);
2318 AST_LIST_UNLOCK(&agents);
2323 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);
2328 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");
2331 if (exitifnoagentid)
2337 /*! \brief Part of PBX channel interface */
2338 static int agent_devicestate(const char *data)
2340 struct agent_pvt *p;
2342 ast_group_t groupmatch;
2344 int res = AST_DEVICE_INVALID;
2347 if ((s[0] == '@') && (sscanf(s + 1, "%30d", &groupoff) == 1))
2348 groupmatch = (1 << groupoff);
2349 else if ((s[0] == ':') && (sscanf(s + 1, "%30d", &groupoff) == 1)) {
2350 groupmatch = (1 << groupoff);
2354 /* Check actual logged in agents first */
2355 AST_LIST_LOCK(&agents);
2356 AST_LIST_TRAVERSE(&agents, p, list) {
2357 ast_mutex_lock(&p->lock);
2358 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2360 if (res != AST_DEVICE_INUSE)
2361 res = AST_DEVICE_BUSY;
2363 if (res == AST_DEVICE_BUSY)
2364 res = AST_DEVICE_INUSE;
2366 if (res == AST_DEVICE_INVALID)
2367 res = AST_DEVICE_UNKNOWN;
2368 } else if (res == AST_DEVICE_INVALID)
2369 res = AST_DEVICE_UNAVAILABLE;
2371 if (!strcmp(data, p->agent)) {
2372 ast_mutex_unlock(&p->lock);
2376 ast_mutex_unlock(&p->lock);
2378 AST_LIST_UNLOCK(&agents);
2383 * \note This function expects the agent list to be locked
2385 static struct agent_pvt *find_agent(char *agentid)
2387 struct agent_pvt *cur;
2389 AST_LIST_TRAVERSE(&agents, cur, list) {
2390 if (!strcmp(cur->agent, agentid))
2397 static int function_agent(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
2400 AST_DECLARE_APP_ARGS(args,
2401 AST_APP_ARG(agentid);
2405 struct agent_pvt *agent;
2409 if (ast_strlen_zero(data)) {
2410 ast_log(LOG_WARNING, "The AGENT function requires an argument - agentid!\n");
2414 parse = ast_strdupa(data);
2416 AST_NONSTANDARD_APP_ARGS(args, parse, ':');
2418 args.item = "status";
2420 AST_LIST_LOCK(&agents);
2422 if (!(agent = find_agent(args.agentid))) {
2423 AST_LIST_UNLOCK(&agents);
2424 ast_log(LOG_WARNING, "Agent '%s' not found!\n", args.agentid);
2428 if (!strcasecmp(args.item, "status")) {
2429 char *status = "LOGGEDOUT";
2431 status = "LOGGEDIN";
2433 ast_copy_string(buf, status, len);
2434 } else if (!strcasecmp(args.item, "password"))
2435 ast_copy_string(buf, agent->password, len);
2436 else if (!strcasecmp(args.item, "name"))
2437 ast_copy_string(buf, agent->name, len);
2438 else if (!strcasecmp(args.item, "mohclass"))
2439 ast_copy_string(buf, agent->moh, len);
2440 else if (!strcasecmp(args.item, "channel")) {
2442 ast_channel_lock(agent->chan);
2443 ast_copy_string(buf, ast_channel_name(agent->chan), len);
2444 ast_channel_unlock(agent->chan);
2445 tmp = strrchr(buf, '-');
2449 } else if (!strcasecmp(args.item, "fullchannel")) {
2451 ast_channel_lock(agent->chan);
2452 ast_copy_string(buf, ast_channel_name(agent->chan), len);
2453 ast_channel_unlock(agent->chan);
2455 } else if (!strcasecmp(args.item, "exten")) {
2459 AST_LIST_UNLOCK(&agents);
2464 static struct ast_custom_function agent_function = {
2466 .read = function_agent,
2471 * \brief Callback used to generate the agents tree.
2472 * \param[in] search The search pattern tree.
2473 * \retval NULL on error.
2474 * \retval non-NULL The generated tree.
2476 static int agents_data_provider_get(const struct ast_data_search *search,
2477 struct ast_data *data_root)
2479 struct agent_pvt *p;
2480 struct ast_data *data_agent, *data_channel, *data_talkingto;
2482 AST_LIST_LOCK(&agents);
2483 AST_LIST_TRAVERSE(&agents, p, list) {
2484 struct ast_channel *owner;
2486 data_agent = ast_data_add_node(data_root, "agent");
2491 ast_mutex_lock(&p->lock);
2492 owner = agent_lock_owner(p);
2494 if (!(p->pending)) {
2495 ast_data_add_str(data_agent, "id", p->agent);
2496 ast_data_add_structure(agent_pvt, data_agent, p);
2498 ast_data_add_bool(data_agent, "logged", p->chan ? 1 : 0);
2500 data_channel = ast_data_add_node(data_agent, "loggedon");
2501 if (!data_channel) {
2502 ast_mutex_unlock(&p->lock);
2503 ast_data_remove_node(data_root, data_agent);
2505 ast_channel_unlock(owner);
2506 owner = ast_channel_unref(owner);
2510 ast_channel_data_add_structure(data_channel, p->chan, 0);
2511 if (owner && ast_bridged_channel(owner)) {
2512 data_talkingto = ast_data_add_node(data_agent, "talkingto");
2513 if (!data_talkingto) {
2514 ast_mutex_unlock(&p->lock);
2515 ast_data_remove_node(data_root, data_agent);
2517 ast_channel_unlock(owner);
2518 owner = ast_channel_unref(owner);
2522 ast_channel_data_add_structure(data_talkingto, ast_bridged_channel(owner), 0);
2525 ast_data_add_node(data_agent, "talkingto");
2526 ast_data_add_node(data_agent, "loggedon");
2528 ast_data_add_str(data_agent, "musiconhold", p->moh);
2532 ast_channel_unlock(owner);
2533 owner = ast_channel_unref(owner);
2536 ast_mutex_unlock(&p->lock);
2538 /* if this agent doesn't match remove the added agent. */
2539 if (!ast_data_search_match(search, data_agent)) {
2540 ast_data_remove_node(data_root, data_agent);
2543 AST_LIST_UNLOCK(&agents);
2548 static const struct ast_data_handler agents_data_provider = {
2549 .version = AST_DATA_HANDLER_VERSION,
2550 .get = agents_data_provider_get
2553 static const struct ast_data_entry agents_data_providers[] = {
2554 AST_DATA_ENTRY("asterisk/channel/agent/list", &agents_data_provider),
2558 * \brief Initialize the Agents module.
2559 * This function is being called by Asterisk when loading the module.
2560 * Among other things it registers applications, cli commands and reads the cofiguration file.
2562 * \returns int Always 0.
2564 static int load_module(void)
2566 if (!(agent_tech.capabilities = ast_format_cap_alloc())) {
2567 ast_log(LOG_ERROR, "ast_format_cap_alloc_nolock fail.\n");
2568 return AST_MODULE_LOAD_FAILURE;
2570 ast_format_cap_add_all(agent_tech.capabilities);
2571 /* Make sure we can register our agent channel type */
2572 if (ast_channel_register(&agent_tech)) {
2573 agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2574 ast_log(LOG_ERROR, "Unable to register channel class 'Agent'\n");
2575 return AST_MODULE_LOAD_FAILURE;
2577 /* Read in the config */
2578 if (!read_agent_config(0)) {
2579 agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2580 return AST_MODULE_LOAD_DECLINE;
2582 /* Dialplan applications */
2583 ast_register_application_xml(app, login_exec);
2584 ast_register_application_xml(app3, agentmonitoroutgoing_exec);
2587 ast_data_register_multiple(agents_data_providers, ARRAY_LEN(agents_data_providers));
2589 /* Manager commands */
2590 ast_manager_register_xml("Agents", EVENT_FLAG_AGENT, action_agents);
2591 ast_manager_register_xml("AgentLogoff", EVENT_FLAG_AGENT, action_agent_logoff);
2594 ast_cli_register_multiple(cli_agents, ARRAY_LEN(cli_agents));
2596 /* Dialplan Functions */
2597 ast_custom_function_register(&agent_function);
2599 return AST_MODULE_LOAD_SUCCESS;
2602 static int reload(void)
2604 return read_agent_config(1);
2607 static int unload_module(void)
2609 struct agent_pvt *p;
2610 /* First, take us out of the channel loop */
2611 ast_channel_unregister(&agent_tech);
2612 /* Unregister dialplan functions */
2613 ast_custom_function_unregister(&agent_function);
2614 /* Unregister CLI commands */
2615 ast_cli_unregister_multiple(cli_agents, ARRAY_LEN(cli_agents));
2616 /* Unregister dialplan applications */
2617 ast_unregister_application(app);
2618 ast_unregister_application(app3);
2619 /* Unregister manager command */
2620 ast_manager_unregister("Agents");
2621 ast_manager_unregister("AgentLogoff");
2622 /* Unregister the data tree */
2623 ast_data_unregister(NULL);
2624 /* Unregister channel */
2625 AST_LIST_LOCK(&agents);
2626 /* Hangup all interfaces if they have an owner */
2627 while ((p = AST_LIST_REMOVE_HEAD(&agents, list))) {
2629 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2632 AST_LIST_UNLOCK(&agents);
2634 agent_tech.capabilities = ast_format_cap_destroy(agent_tech.capabilities);
2638 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Agent Proxy Channel",
2639 .load = load_module,
2640 .unload = unload_module,
2642 .load_pri = AST_MODPRI_CHANNEL_DRIVER,
2643 .nonoptreq = "res_monitor,chan_local",