2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Agents
6 * Copyright (C) 1999 - 2005, Digium Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
18 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <sys/signal.h>
28 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
30 #include "asterisk/lock.h"
31 #include "asterisk/channel.h"
32 #include "asterisk/config.h"
33 #include "asterisk/logger.h"
34 #include "asterisk/module.h"
35 #include "asterisk/pbx.h"
36 #include "asterisk/options.h"
37 #include "asterisk/lock.h"
38 #include "asterisk/sched.h"
39 #include "asterisk/io.h"
40 #include "asterisk/rtp.h"
41 #include "asterisk/acl.h"
42 #include "asterisk/callerid.h"
43 #include "asterisk/file.h"
44 #include "asterisk/cli.h"
45 #include "asterisk/app.h"
46 #include "asterisk/musiconhold.h"
47 #include "asterisk/manager.h"
48 #include "asterisk/features.h"
49 #include "asterisk/utils.h"
50 #include "asterisk/causes.h"
51 #include "asterisk/astdb.h"
53 static const char desc[] = "Agent Proxy Channel";
54 static const char channeltype[] = "Agent";
55 static const char tdesc[] = "Call Agent Proxy Channel";
56 static const char config[] = "agents.conf";
58 static const char app[] = "AgentLogin";
59 static const char app2[] = "AgentCallbackLogin";
60 static const char app3[] = "AgentMonitorOutgoing";
62 static const char synopsis[] = "Call agent login";
63 static const char synopsis2[] = "Call agent callback login";
64 static const char synopsis3[] = "Record agent's outgoing call";
66 static const char descrip[] =
67 " AgentLogin([AgentNo][|options]):\n"
68 "Asks the agent to login to the system. Always returns -1. While\n"
69 "logged in, the agent can receive calls and will hear a 'beep'\n"
70 "when a new call comes in. The agent can dump the call by pressing\n"
72 "The option string may contain zero or more of the following characters:\n"
73 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
75 static const char descrip2[] =
76 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
77 "Asks the agent to login to the system with callback.\n"
78 "The agent's callback extension is called (optionally with the specified\n"
80 "The option string may contain zero or more of the following characters:\n"
81 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
83 static const char descrip3[] =
84 " AgentMonitorOutgoing([options]):\n"
85 "Tries to figure out the id of the agent who is placing outgoing call based on\n"
86 "comparision of the callerid of the current interface and the global variable \n"
87 "placed by the AgentCallbackLogin application. That's why it should be used only\n"
88 "with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent \n"
89 "instead of Monitor application. That have to be configured in the agents.conf file.\n"
91 "Normally the app returns 0 unless the options are passed. Also if the callerid or\n"
92 "the agentid are not specified it'll look for n+101 priority.\n"
94 " 'd' - make the app return -1 if there is an error condition and there is\n"
95 " no extension n+101\n"
96 " 'c' - change the CDR so that the source of the call is 'Agent/agent_id'\n"
97 " 'n' - don't generate the warnings when there is no callerid or the\n"
98 " agentid is not known.\n"
99 " It's handy if you want to have one context for agent and non-agent calls.\n";
101 static const char mandescr_agents[] =
102 "Description: Will list info about all possible agents.\n"
105 static char moh[80] = "default";
107 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
108 #define AST_MAX_BUF 256
109 #define AST_MAX_FILENAME_LEN 256
111 /* Persistent Agents astdb family */
112 static const char pa_family[] = "/Agents";
113 /* The maximum lengh of each persistent member agent database entry */
114 #define PA_MAX_LEN 2048
115 /* queues.conf [general] option */
116 static int persistent_agents = 0;
117 static void dump_agents(void);
119 static ast_group_t group;
120 static int autologoff;
121 static int wrapuptime;
124 static int maxlogintries = 3;
125 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
127 static int usecnt =0;
128 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
130 /* Protect the interface list (of pvt's) */
131 AST_MUTEX_DEFINE_STATIC(agentlock);
133 static int recordagentcalls = 0;
134 static char recordformat[AST_MAX_BUF] = "";
135 static char recordformatext[AST_MAX_BUF] = "";
136 static int createlink = 0;
137 static char urlprefix[AST_MAX_BUF] = "";
138 static char savecallsin[AST_MAX_BUF] = "";
139 static int updatecdr = 0;
140 static char beep[AST_MAX_BUF] = "beep";
142 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
144 static struct agent_pvt {
145 ast_mutex_t lock; /* Channel private lock */
146 int dead; /* Poised for destruction? */
147 int pending; /* Not a real agent -- just pending a match */
148 int abouttograb; /* About to grab */
149 int autologoff; /* Auto timeout time */
150 int ackcall; /* ackcall */
151 time_t loginstart; /* When agent first logged in (0 when logged off) */
152 time_t start; /* When call started */
153 struct timeval lastdisc; /* When last disconnected */
154 int wrapuptime; /* Wrapup time in ms */
155 ast_group_t group; /* Group memberships */
156 int acknowledged; /* Acknowledged */
157 char moh[80]; /* Which music on hold */
158 char agent[AST_MAX_AGENT]; /* Agent ID */
159 char password[AST_MAX_AGENT]; /* Password for Agent login */
160 char name[AST_MAX_AGENT];
161 ast_mutex_t app_lock; /* Synchronization between owning applications */
162 volatile pthread_t owning_app; /* Owning application thread id */
163 volatile int app_sleep_cond; /* Sleep condition for the login app */
164 struct ast_channel *owner; /* Agent */
165 char loginchan[80]; /* channel they logged in from */
166 char logincallerid[80]; /* Caller ID they had when they logged in */
167 struct ast_channel *chan; /* Channel we use */
168 struct agent_pvt *next; /* Agent */
171 #define CHECK_FORMATS(ast, p) do { \
173 if (ast->nativeformats != p->chan->nativeformats) { \
174 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
175 /* Native formats changed, reset things */ \
176 ast->nativeformats = p->chan->nativeformats; \
177 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
178 ast_set_read_format(ast, ast->readformat); \
179 ast_set_write_format(ast, ast->writeformat); \
181 if (p->chan->readformat != ast->rawreadformat) \
182 ast_set_read_format(p->chan, ast->rawreadformat); \
183 if (p->chan->writeformat != ast->rawwriteformat) \
184 ast_set_write_format(p->chan, ast->rawwriteformat); \
188 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
189 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
190 totally impractical combinations XXX */
192 #define CLEANUP(ast, p) do { \
195 for (x=0;x<AST_MAX_FDS;x++) {\
196 if (x != AST_MAX_FDS - 2) \
197 ast->fds[x] = p->chan->fds[x]; \
199 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
203 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause);
204 static int agent_devicestate(void *data);
205 static int agent_digit(struct ast_channel *ast, char digit);
206 static int agent_call(struct ast_channel *ast, char *dest, int timeout);
207 static int agent_hangup(struct ast_channel *ast);
208 static int agent_answer(struct ast_channel *ast);
209 static struct ast_frame *agent_read(struct ast_channel *ast);
210 static int agent_write(struct ast_channel *ast, struct ast_frame *f);
211 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen);
212 static int agent_indicate(struct ast_channel *ast, int condition);
213 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
214 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge);
216 static const struct ast_channel_tech agent_tech = {
218 .description = tdesc,
220 .requester = agent_request,
221 .devicestate = agent_devicestate,
222 .send_digit = agent_digit,
224 .hangup = agent_hangup,
225 .answer = agent_answer,
227 .write = agent_write,
228 .send_html = agent_sendhtml,
229 .exception = agent_read,
230 .indicate = agent_indicate,
231 .fixup = agent_fixup,
232 .bridged_channel = agent_bridgedchannel,
235 static void agent_unlink(struct agent_pvt *agent)
237 struct agent_pvt *p, *prev;
243 prev->next = agent->next;
245 agents = agent->next;
253 static struct agent_pvt *add_agent(char *agent, int pending)
258 char *password = NULL;
261 struct agent_pvt *p, *prev;
263 args = ast_strdupa(agent);
265 if ((argc = ast_separate_app_args(args, ',', argv, sizeof(argv) / sizeof(argv[0])))) {
269 while (*password && *password < 33) password++;
273 while (*name && *name < 33) name++;
276 ast_log(LOG_WARNING, "A blank agent line!\n");
282 if (!pending && !strcmp(p->agent, agt))
288 p = malloc(sizeof(struct agent_pvt));
290 memset(p, 0, sizeof(struct agent_pvt));
291 strncpy(p->agent, agt, sizeof(p->agent) -1);
292 ast_mutex_init(&p->lock);
293 ast_mutex_init(&p->app_lock);
294 p->owning_app = (pthread_t) -1;
295 p->app_sleep_cond = 1;
297 p->pending = pending;
309 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
310 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
311 strncpy(p->moh, moh, sizeof(p->moh) - 1);
312 p->ackcall = ackcall;
313 p->autologoff = autologoff;
315 /* If someone reduces the wrapuptime and reloads, we want it
316 * to change the wrapuptime immediately on all calls */
317 if (p->wrapuptime > wrapuptime) {
319 gettimeofday(&now, NULL);
321 /* We won't be pedantic and check the tv_usec val */
322 if (p->lastdisc.tv_sec > (now.tv_sec + wrapuptime/1000)) {
323 p->lastdisc.tv_sec = now.tv_sec + wrapuptime/1000;
324 p->lastdisc.tv_usec = now.tv_usec;
327 p->wrapuptime = wrapuptime;
336 static int agent_cleanup(struct agent_pvt *p)
338 struct ast_channel *chan = p->owner;
340 chan->tech_pvt = NULL;
341 p->app_sleep_cond = 1;
342 /* Release ownership of the agent to other threads (presumably running the login app). */
343 ast_mutex_unlock(&p->app_lock);
345 ast_channel_free(chan);
347 ast_mutex_destroy(&p->lock);
348 ast_mutex_destroy(&p->app_lock);
354 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
356 static int agent_answer(struct ast_channel *ast)
358 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
362 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
364 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
365 char filename[AST_MAX_BUF];
370 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
371 /* substitute . for - */
372 if ((pointer = strchr(filename, '.')))
374 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
375 ast_monitor_start(ast, recordformat, tmp, needlock);
376 ast_monitor_setjoinfiles(ast, 1);
377 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
379 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
382 ast->cdr = ast_cdr_alloc();
383 ast_cdr_setuserfield(ast, tmp2);
386 ast_log(LOG_ERROR, "Recording already started on that call.\n");
390 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
392 return __agent_start_monitoring(ast, ast->tech_pvt, needlock);
395 static struct ast_frame *agent_read(struct ast_channel *ast)
397 struct agent_pvt *p = ast->tech_pvt;
398 struct ast_frame *f = NULL;
399 static struct ast_frame null_frame = { AST_FRAME_NULL, };
400 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
401 ast_mutex_lock(&p->lock);
402 CHECK_FORMATS(ast, p);
404 ast_copy_flags(p->chan, ast, AST_FLAG_EXCEPTION);
405 if (ast->fdno == AST_MAX_FDS - 3)
406 p->chan->fdno = AST_MAX_FDS - 2;
408 p->chan->fdno = ast->fdno;
409 f = ast_read(p->chan);
413 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
415 p->chan->_bridge = NULL;
416 /* Note that we don't hangup if it's not a callback because Asterisk will do it
417 for us when the PBX instance that called login finishes */
418 if (!ast_strlen_zero(p->loginchan)) {
420 ast_log(LOG_DEBUG, "Bridge on '%s' being cleared (2)\n", p->chan->name);
422 if (p->wrapuptime && p->acknowledged) {
423 gettimeofday(&p->lastdisc, NULL);
424 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
425 if (p->lastdisc.tv_usec > 1000000) {
426 p->lastdisc.tv_usec -= 1000000;
427 p->lastdisc.tv_sec++;
429 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
436 /* if acknowledgement is not required, and the channel is up, we may have missed
437 an AST_CONTROL_ANSWER (if there was one), so mark the call acknowledged anyway */
438 if (!p->ackcall && !p->acknowledged && p->chan->_state == AST_STATE_UP)
440 switch (f->frametype) {
441 case AST_FRAME_CONTROL:
442 if (f->subclass == AST_CONTROL_ANSWER) {
444 if (option_verbose > 2)
445 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
446 /* Don't pass answer along */
451 /* Use the builtin answer frame for the
452 recording start check below. */
459 if (!p->acknowledged && (f->subclass == '#')) {
460 if (option_verbose > 2)
461 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
465 } else if (f->subclass == '*') {
466 /* terminates call */
471 case AST_FRAME_VOICE:
472 /* don't pass voice until the call is acknowledged */
473 if (!p->acknowledged) {
482 if (p->chan && !p->chan->_bridge) {
483 if (strcasecmp(p->chan->type, "Local")) {
484 p->chan->_bridge = ast;
486 ast_log(LOG_DEBUG, "Bridge on '%s' being set to '%s' (3)\n", p->chan->name, p->chan->_bridge->name);
489 ast_mutex_unlock(&p->lock);
490 if (recordagentcalls && f == &answer_frame)
491 agent_start_monitoring(ast,0);
495 static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen)
497 struct agent_pvt *p = ast->tech_pvt;
499 ast_mutex_lock(&p->lock);
501 res = ast_channel_sendhtml(p->chan, subclass, data, datalen);
502 ast_mutex_unlock(&p->lock);
506 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
508 struct agent_pvt *p = ast->tech_pvt;
510 CHECK_FORMATS(ast, p);
511 ast_mutex_lock(&p->lock);
513 if ((f->frametype != AST_FRAME_VOICE) ||
514 (f->subclass == p->chan->writeformat)) {
515 res = ast_write(p->chan, f);
517 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
523 ast_mutex_unlock(&p->lock);
527 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
529 struct agent_pvt *p = newchan->tech_pvt;
530 ast_mutex_lock(&p->lock);
531 if (p->owner != oldchan) {
532 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
533 ast_mutex_unlock(&p->lock);
537 ast_mutex_unlock(&p->lock);
541 static int agent_indicate(struct ast_channel *ast, int condition)
543 struct agent_pvt *p = ast->tech_pvt;
545 ast_mutex_lock(&p->lock);
547 res = ast_indicate(p->chan, condition);
550 ast_mutex_unlock(&p->lock);
554 static int agent_digit(struct ast_channel *ast, char digit)
556 struct agent_pvt *p = ast->tech_pvt;
558 ast_mutex_lock(&p->lock);
560 res = p->chan->tech->send_digit(p->chan, digit);
563 ast_mutex_unlock(&p->lock);
567 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
569 struct agent_pvt *p = ast->tech_pvt;
572 ast_mutex_lock(&p->lock);
576 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
577 newstate = AST_STATE_DIALING;
580 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
583 ast_mutex_unlock(&p->lock);
585 ast_setstate(ast, newstate);
587 } else if (!ast_strlen_zero(p->loginchan)) {
589 /* Call on this agent */
590 if (option_verbose > 2)
591 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
592 if (p->chan->cid.cid_num)
593 free(p->chan->cid.cid_num);
594 if (ast->cid.cid_num)
595 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
597 p->chan->cid.cid_num = NULL;
598 if (p->chan->cid.cid_name)
599 free(p->chan->cid.cid_name);
600 if (ast->cid.cid_name)
601 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
603 p->chan->cid.cid_name = NULL;
604 ast_channel_inherit_variables(ast, p->chan);
605 res = ast_call(p->chan, p->loginchan, 0);
607 ast_mutex_unlock(&p->lock);
610 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
611 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
612 res = ast_streamfile(p->chan, beep, p->chan->language);
613 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
615 res = ast_waitstream(p->chan, "");
616 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
619 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
620 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
622 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
629 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
630 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
632 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
636 /* Call is immediately up, or might need ack */
638 newstate = AST_STATE_RINGING;
640 newstate = AST_STATE_UP;
641 if (recordagentcalls)
642 agent_start_monitoring(ast,0);
648 ast_mutex_unlock(&p->lock);
650 ast_setstate(ast, newstate);
654 /* store/clear the global variable that stores agentid based on the callerid */
655 static void set_agentbycallerid(const struct agent_pvt *agent)
657 char buf[AST_MAX_BUF];
659 /* if there is no Caller ID, nothing to do */
660 if (!agent->logincallerid[0])
663 snprintf(buf, sizeof(buf), "%s_%s",GETAGENTBYCALLERID, agent->logincallerid);
664 pbx_builtin_setvar_helper(NULL, buf, ast_strlen_zero(agent->loginchan) ? NULL : agent->agent);
667 static int agent_hangup(struct ast_channel *ast)
669 struct agent_pvt *p = ast->tech_pvt;
671 ast_mutex_lock(&p->lock);
673 ast->tech_pvt = NULL;
674 p->app_sleep_cond = 1;
677 /* if they really are hung up then set start to 0 so the test
678 * later if we're called on an already downed channel
679 * doesn't cause an agent to be logged out like when
680 * agent_request() is followed immediately by agent_hangup()
681 * as in apps/app_chanisavail.c:chanavail_exec()
684 ast_mutex_lock(&usecnt_lock);
686 ast_mutex_unlock(&usecnt_lock);
688 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
689 if (p->start && (ast->_state != AST_STATE_UP)) {
690 howlong = time(NULL) - p->start;
692 } else if (ast->_state == AST_STATE_RESERVED) {
697 p->chan->_bridge = NULL;
698 /* If they're dead, go ahead and hang up on the agent now */
699 if (!ast_strlen_zero(p->loginchan)) {
700 /* Store last disconnect time */
701 if (p->wrapuptime && p->acknowledged) {
702 gettimeofday(&p->lastdisc, NULL);
703 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
704 if (p->lastdisc.tv_usec >= 1000000) {
705 p->lastdisc.tv_usec -= 1000000;
706 p->lastdisc.tv_sec++;
708 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
710 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
712 /* Recognize the hangup and pass it along immediately */
716 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
717 if (howlong && p->autologoff && (howlong > p->autologoff)) {
718 char agent[AST_MAX_AGENT] = "";
719 long logintime = time(NULL) - p->loginstart;
721 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
722 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
726 "Reason: Autologoff\r\n"
728 p->agent, p->loginchan, logintime, ast->uniqueid);
729 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
730 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
731 p->loginchan[0] = '\0';
732 set_agentbycallerid(p);
733 p->logincallerid[0] = '\0';
735 } else if (p->dead) {
736 ast_mutex_lock(&p->chan->lock);
737 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
738 ast_mutex_unlock(&p->chan->lock);
740 ast_mutex_lock(&p->chan->lock);
741 ast_moh_start(p->chan, p->moh);
742 ast_mutex_unlock(&p->chan->lock);
746 ast_mutex_unlock(&p->lock);
747 /* Release ownership of the agent to other threads (presumably running the login app). */
748 ast_mutex_unlock(&p->app_lock);
749 } else if (p->dead) {
750 /* Go ahead and lose it */
751 ast_mutex_unlock(&p->lock);
752 /* Release ownership of the agent to other threads (presumably running the login app). */
753 ast_mutex_unlock(&p->app_lock);
755 ast_mutex_unlock(&p->lock);
756 /* Release ownership of the agent to other threads (presumably running the login app). */
757 ast_mutex_unlock(&p->app_lock);
760 ast_mutex_unlock(&p->lock);
761 ast_device_state_changed("Agent/%s", p->agent);
764 ast_mutex_lock(&agentlock);
766 ast_mutex_unlock(&agentlock);
768 if (p->abouttograb) {
769 /* Let the "about to grab" thread know this isn't valid anymore, and let it
772 } else if (p->dead) {
773 ast_mutex_destroy(&p->lock);
774 ast_mutex_destroy(&p->app_lock);
778 /* Not dead -- check availability now */
779 ast_mutex_lock(&p->lock);
780 /* Store last disconnect time */
781 gettimeofday(&p->lastdisc, NULL);
782 ast_mutex_unlock(&p->lock);
784 /* Release ownership of the agent to other threads (presumably running the login app). */
785 ast_mutex_unlock(&p->app_lock);
790 static int agent_cont_sleep( void *data )
796 p = (struct agent_pvt *)data;
798 ast_mutex_lock(&p->lock);
799 res = p->app_sleep_cond;
800 if (p->lastdisc.tv_sec) {
801 gettimeofday(&tv, NULL);
802 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
803 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
806 ast_mutex_unlock(&p->lock);
809 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
814 static int agent_ack_sleep( void *data )
821 /* Wait a second and look for something */
823 p = (struct agent_pvt *)data;
826 to = ast_waitfor(p->chan, to);
835 f = ast_read(p->chan);
840 if (f->frametype == AST_FRAME_DTMF)
845 ast_mutex_lock(&p->lock);
846 if (!p->app_sleep_cond) {
847 ast_mutex_unlock(&p->lock);
850 } else if (res == '#') {
851 ast_mutex_unlock(&p->lock);
855 ast_mutex_unlock(&p->lock);
863 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
866 struct ast_channel *ret=NULL;
869 p = bridge->tech_pvt;
871 ret = bridge->_bridge;
872 else if (chan == bridge->_bridge)
875 ast_log(LOG_DEBUG, "Asked for bridged channel on '%s'/'%s', returning '%s'\n", chan->name, bridge->name, ret ? ret->name : "<none>");
879 /*--- agent_new: Create new agent channel ---*/
880 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
882 struct ast_channel *tmp;
883 struct ast_frame null_frame = { AST_FRAME_NULL };
886 ast_log(LOG_WARNING, "No channel? :(\n");
890 tmp = ast_channel_alloc(0);
892 tmp->tech = &agent_tech;
894 tmp->nativeformats = p->chan->nativeformats;
895 tmp->writeformat = p->chan->writeformat;
896 tmp->rawwriteformat = p->chan->writeformat;
897 tmp->readformat = p->chan->readformat;
898 tmp->rawreadformat = p->chan->readformat;
899 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
900 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
901 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
903 tmp->nativeformats = AST_FORMAT_SLINEAR;
904 tmp->writeformat = AST_FORMAT_SLINEAR;
905 tmp->rawwriteformat = AST_FORMAT_SLINEAR;
906 tmp->readformat = AST_FORMAT_SLINEAR;
907 tmp->rawreadformat = AST_FORMAT_SLINEAR;
910 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
912 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
913 tmp->type = channeltype;
914 /* Safe, agentlock already held */
915 ast_setstate(tmp, state);
918 ast_mutex_lock(&usecnt_lock);
920 ast_mutex_unlock(&usecnt_lock);
921 ast_update_use_count();
923 /* Wake up and wait for other applications (by definition the login app)
924 * to release this channel). Takes ownership of the agent channel
925 * to this thread only.
926 * For signalling the other thread, ast_queue_frame is used until we
927 * can safely use signals for this purpose. The pselect() needs to be
928 * implemented in the kernel for this.
930 p->app_sleep_cond = 0;
931 if( ast_mutex_trylock(&p->app_lock) )
934 ast_queue_frame(p->chan, &null_frame);
935 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
936 ast_mutex_lock(&p->app_lock);
937 ast_mutex_lock(&p->lock);
941 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
943 tmp->tech_pvt = NULL;
944 p->app_sleep_cond = 1;
945 ast_channel_free( tmp );
946 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
947 ast_mutex_unlock(&p->app_lock);
951 p->owning_app = pthread_self();
952 /* After the above step, there should not be any blockers. */
954 if (ast_test_flag(p->chan, AST_FLAG_BLOCKING)) {
955 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
958 ast_moh_stop(p->chan);
961 ast_log(LOG_WARNING, "Unable to allocate agent channel structure\n");
966 /*--- read_agent_config: Read configuration data (agents.conf) ---*/
967 static int read_agent_config(void)
969 struct ast_config *cfg;
970 struct ast_variable *v;
971 struct agent_pvt *p, *pl, *pn;
978 cfg = ast_config_load(config);
980 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
983 ast_mutex_lock(&agentlock);
989 strncpy(moh, "default", sizeof(moh) - 1);
990 /* set the default recording values */
991 recordagentcalls = 0;
993 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
994 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
996 savecallsin[0] = '\0';
998 /* Read in [general] section for persistance */
999 if ((general_val = ast_variable_retrieve(cfg, "general", "persistentagents")))
1000 persistent_agents = ast_true(general_val);
1002 /* Read in the [agents] section */
1003 v = ast_variable_browse(cfg, "agents");
1005 /* Create the interface list */
1006 if (!strcasecmp(v->name, "agent")) {
1007 add_agent(v->value, 0);
1008 } else if (!strcasecmp(v->name, "group")) {
1009 group = ast_get_group(v->value);
1010 } else if (!strcasecmp(v->name, "autologoff")) {
1011 autologoff = atoi(v->value);
1014 } else if (!strcasecmp(v->name, "ackcall")) {
1015 if (!strcasecmp(v->value, "always"))
1017 else if (ast_true(v->value))
1021 } else if (!strcasecmp(v->name, "wrapuptime")) {
1022 wrapuptime = atoi(v->value);
1025 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
1026 maxlogintries = atoi(v->value);
1027 if (maxlogintries < 0)
1029 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
1030 strcpy(agentgoodbye,v->value);
1031 } else if (!strcasecmp(v->name, "musiconhold")) {
1032 strncpy(moh, v->value, sizeof(moh) - 1);
1033 } else if (!strcasecmp(v->name, "updatecdr")) {
1034 if (ast_true(v->value))
1038 } else if (!strcasecmp(v->name, "recordagentcalls")) {
1039 recordagentcalls = ast_true(v->value);
1040 } else if (!strcasecmp(v->name, "createlink")) {
1041 createlink = ast_true(v->value);
1042 } else if (!strcasecmp(v->name, "recordformat")) {
1043 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
1044 if (!strcasecmp(v->value, "wav49"))
1045 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
1047 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
1048 } else if (!strcasecmp(v->name, "urlprefix")) {
1049 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
1050 if (urlprefix[strlen(urlprefix) - 1] != '/')
1051 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
1052 } else if (!strcasecmp(v->name, "savecallsin")) {
1053 if (v->value[0] == '/')
1054 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
1056 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
1057 if (savecallsin[strlen(savecallsin) - 1] != '/')
1058 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
1059 } else if (!strcasecmp(v->name, "custom_beep")) {
1060 strncpy(beep, v->value, sizeof(beep) - 1);
1074 /* Destroy if appropriate */
1077 ast_mutex_destroy(&p->lock);
1078 ast_mutex_destroy(&p->app_lock);
1081 /* Cause them to hang up */
1082 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1089 ast_mutex_unlock(&agentlock);
1090 ast_config_destroy(cfg);
1094 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
1096 struct ast_channel *chan=NULL, *parent=NULL;
1097 struct agent_pvt *p;
1101 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
1103 ast_mutex_lock(&agentlock);
1106 if (p == newlyavailable) {
1110 ast_mutex_lock(&p->lock);
1111 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1113 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1114 /* We found a pending call, time to merge */
1115 chan = agent_new(newlyavailable, AST_STATE_DOWN);
1118 ast_mutex_unlock(&p->lock);
1121 ast_mutex_unlock(&p->lock);
1125 ast_mutex_unlock(&agentlock);
1126 if (parent && chan) {
1127 if (newlyavailable->ackcall > 1) {
1128 /* Don't do beep here */
1131 if (option_debug > 2)
1132 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1133 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1134 if (option_debug > 2)
1135 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1137 res = ast_waitstream(newlyavailable->chan, "");
1138 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1142 /* Note -- parent may have disappeared */
1143 if (p->abouttograb) {
1144 newlyavailable->acknowledged = 1;
1145 /* Safe -- agent lock already held */
1146 ast_setstate(parent, AST_STATE_UP);
1147 ast_setstate(chan, AST_STATE_UP);
1148 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
1149 /* Go ahead and mark the channel as a zombie so that masquerade will
1150 destroy it for us, and we need not call ast_hangup */
1151 ast_mutex_lock(&parent->lock);
1152 ast_set_flag(chan, AST_FLAG_ZOMBIE);
1153 ast_channel_masquerade(parent, chan);
1154 ast_mutex_unlock(&parent->lock);
1158 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1159 agent_cleanup(newlyavailable);
1163 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1164 agent_cleanup(newlyavailable);
1170 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1172 struct agent_pvt *p;
1175 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1177 ast_mutex_lock(&agentlock);
1180 if (p == newlyavailable) {
1184 ast_mutex_lock(&p->lock);
1185 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1187 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1188 ast_mutex_unlock(&p->lock);
1191 ast_mutex_unlock(&p->lock);
1195 ast_mutex_unlock(&agentlock);
1197 ast_mutex_unlock(&newlyavailable->lock);
1198 if (option_debug > 2)
1199 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1200 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1201 if (option_debug > 2)
1202 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1204 res = ast_waitstream(newlyavailable->chan, "");
1206 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1208 ast_mutex_lock(&newlyavailable->lock);
1213 /*--- agent_request: Part of the Asterisk PBX interface ---*/
1214 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1216 struct agent_pvt *p;
1217 struct ast_channel *chan = NULL;
1219 ast_group_t groupmatch;
1226 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1227 groupmatch = (1 << groupoff);
1228 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
1229 groupmatch = (1 << groupoff);
1235 /* Check actual logged in agents first */
1236 ast_mutex_lock(&agentlock);
1239 ast_mutex_lock(&p->lock);
1240 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1241 ast_strlen_zero(p->loginchan)) {
1244 if (!p->lastdisc.tv_sec) {
1245 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1246 if (!p->owner && p->chan) {
1248 chan = agent_new(p, AST_STATE_DOWN);
1251 ast_mutex_unlock(&p->lock);
1256 ast_mutex_unlock(&p->lock);
1262 ast_mutex_lock(&p->lock);
1263 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1264 if (p->chan || !ast_strlen_zero(p->loginchan))
1266 gettimeofday(&tv, NULL);
1268 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1270 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1271 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1272 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1273 if (!p->owner && p->chan) {
1274 /* Could still get a fixed agent */
1275 chan = agent_new(p, AST_STATE_DOWN);
1276 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1277 /* Adjustable agent */
1278 p->chan = ast_request("Local", format, p->loginchan, cause);
1280 chan = agent_new(p, AST_STATE_DOWN);
1283 ast_mutex_unlock(&p->lock);
1288 ast_mutex_unlock(&p->lock);
1293 if (!chan && waitforagent) {
1294 /* No agent available -- but we're requesting to wait for one.
1295 Allocate a place holder */
1298 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1299 p = add_agent(data, 1);
1300 p->group = groupmatch;
1301 chan = agent_new(p, AST_STATE_DOWN);
1303 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1306 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1309 *cause = AST_CAUSE_BUSY;
1311 *cause = AST_CAUSE_UNREGISTERED;
1312 ast_mutex_unlock(&agentlock);
1316 static int powerof(unsigned int v)
1319 for (x=0;x<32;x++) {
1320 if (v & (1 << x)) return x;
1325 /*--- action_agents: Manager routine for listing channels */
1326 static int action_agents(struct mansession *s, struct message *m)
1328 struct agent_pvt *p;
1329 char *username = NULL;
1330 char *loginChan = NULL;
1331 char *talkingtoChan = NULL;
1332 char *status = NULL;
1334 ast_mutex_lock(&agentlock);
1337 ast_mutex_lock(&p->lock);
1340 AGENT_LOGGEDOFF - Agent isn't logged in
1341 AGENT_IDLE - Agent is logged in, and waiting for call
1342 AGENT_ONCALL - Agent is logged in, and on a call
1343 AGENT_UNKNOWN - Don't know anything about agent. Shouldn't ever get this. */
1345 if(!ast_strlen_zero(p->name)) {
1351 /* Set a default status. It 'should' get changed. */
1352 status = "AGENT_UNKNOWN";
1355 loginChan = p->loginchan;
1356 if(p->owner && p->owner->_bridge) {
1357 talkingtoChan = p->chan->cid.cid_num;
1358 status = "AGENT_ONCALL";
1360 talkingtoChan = "n/a";
1361 status = "AGENT_IDLE";
1363 } else if(!ast_strlen_zero(p->loginchan)) {
1364 loginChan = p->loginchan;
1365 talkingtoChan = "n/a";
1366 status = "AGENT_IDLE";
1367 if(p->acknowledged) {
1368 sprintf(loginChan, " %s (Confirmed)", loginChan);
1372 talkingtoChan = "n/a";
1373 status = "AGENT_LOGGEDOFF";
1376 ast_cli(s->fd, "Event: Agents\r\n"
1380 "LoggedInChan: %s\r\n"
1381 "LoggedInTime: %ld\r\n"
1384 p->agent,p->name,status,loginChan,p->loginstart,talkingtoChan);
1385 ast_mutex_unlock(&p->lock);
1388 ast_mutex_unlock(&agentlock);
1392 static int agent_logoff_cmd(int fd, int argc, char **argv)
1394 struct agent_pvt *p;
1395 char *agent = argv[2] + 6;
1398 if (argc < 3 || argc > 4)
1399 return RESULT_SHOWUSAGE;
1400 if (argc == 4 && strcasecmp(argv[3], "soft"))
1401 return RESULT_SHOWUSAGE;
1403 for (p=agents; p; p=p->next) {
1404 if (!strcasecmp(p->agent, agent)) {
1407 ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
1410 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
1413 logintime = time(NULL) - p->loginstart;
1416 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1419 "Logintime: %ld\r\n",
1420 p->agent, p->loginchan, logintime);
1421 ast_queue_log("NONE", "NONE", agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "CommandLogoff");
1422 p->loginchan[0] = '\0';
1423 set_agentbycallerid(p);
1424 p->logincallerid[0] = '\0';
1425 ast_cli(fd, "Logging out %s\n", agent);
1426 ast_device_state_changed("Agent/%s", p->agent);
1427 if (persistent_agents)
1432 return RESULT_SUCCESS;
1435 static char *complete_agent_logoff_cmd(char *line, char *word, int pos, int state)
1437 struct agent_pvt *p;
1438 char name[AST_MAX_AGENT];
1442 for (p=agents; p; p=p->next) {
1443 snprintf(name, sizeof(name), "Agent/%s", p->agent);
1444 if (!strncasecmp(word, name, strlen(word))) {
1445 if (++which > state) {
1446 return strdup(name);
1450 } else if (pos == 3 && state == 0) {
1451 return strdup("soft");
1456 /*--- agents_show: Show agents in cli ---*/
1457 static int agents_show(int fd, int argc, char **argv)
1459 struct agent_pvt *p;
1460 char username[AST_MAX_BUF];
1461 char location[AST_MAX_BUF] = "";
1462 char talkingto[AST_MAX_BUF] = "";
1463 char moh[AST_MAX_BUF];
1464 int count_agents = 0; /* Number of agents configured */
1465 int online_agents = 0; /* Number of online agents */
1466 int offline_agents = 0; /* Number of offline agents */
1468 return RESULT_SHOWUSAGE;
1469 ast_mutex_lock(&agentlock);
1472 ast_mutex_lock(&p->lock);
1475 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1477 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1479 if (!ast_strlen_zero(p->name))
1480 snprintf(username, sizeof(username), "(%s) ", p->name);
1484 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1485 if (p->owner && ast_bridged_channel(p->owner)) {
1486 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1488 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1491 } else if (!ast_strlen_zero(p->loginchan)) {
1492 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1493 talkingto[0] = '\0';
1495 if (p->acknowledged)
1496 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1498 strncpy(location, "not logged in", sizeof(location) - 1);
1499 talkingto[0] = '\0';
1502 if (!ast_strlen_zero(p->moh))
1503 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1504 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1505 username, location, talkingto, moh);
1508 ast_mutex_unlock(&p->lock);
1511 ast_mutex_unlock(&agentlock);
1512 if ( !count_agents ) {
1513 ast_cli(fd, "No Agents are configured in %s\n",config);
1515 ast_cli(fd, "%d agents configured [%d online , %d offline]\n",count_agents, online_agents, offline_agents);
1517 return RESULT_SUCCESS;
1520 static char show_agents_usage[] =
1521 "Usage: show agents\n"
1522 " Provides summary information on agents.\n";
1524 static char agent_logoff_usage[] =
1525 "Usage: agent logoff <channel> [soft]\n"
1526 " Sets an agent as no longer logged in.\n"
1527 " If 'soft' is specified, do not hangup existing calls.\n";
1529 static struct ast_cli_entry cli_show_agents = {
1530 { "show", "agents", NULL }, agents_show,
1531 "Show status of agents", show_agents_usage, NULL };
1533 static struct ast_cli_entry cli_agent_logoff = {
1534 { "agent", "logoff", NULL }, agent_logoff_cmd,
1535 "Sets an agent offline", agent_logoff_usage, complete_agent_logoff_cmd };
1537 STANDARD_LOCAL_USER;
1540 /*--- __login_exec: Log in agent application ---*/
1541 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1545 int max_login_tries = maxlogintries;
1546 struct agent_pvt *p;
1547 struct localuser *u;
1549 int login_state = 0;
1550 char user[AST_MAX_AGENT] = "";
1551 char pass[AST_MAX_AGENT];
1552 char agent[AST_MAX_AGENT] = "";
1553 char xpass[AST_MAX_AGENT] = "";
1556 char *opt_user = NULL;
1557 char *options = NULL;
1560 char *tmpoptions = NULL;
1561 char *context = NULL;
1563 int play_announcement = 1;
1564 char agent_goodbye[AST_MAX_FILENAME_LEN];
1565 int update_cdr = updatecdr;
1566 char *filename = "agent-loginok";
1568 strcpy(agent_goodbye, agentgoodbye);
1571 /* Parse the arguments XXX Check for failure XXX */
1572 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1574 /* Set Channel Specific Login Overrides */
1575 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1576 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1577 if (max_login_tries < 0)
1578 max_login_tries = 0;
1579 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1580 if (option_verbose > 2)
1581 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTMAXLOGINTRIES=%s, setting max_login_tries to: %d on Channel '%s'.\n",tmpoptions,max_login_tries,chan->name);
1583 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1584 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1588 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1589 if (option_verbose > 2)
1590 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1592 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && !ast_strlen_zero(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1593 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1594 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1595 if (option_verbose > 2)
1596 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1598 /* End Channel Specific Login Overrides */
1599 /* Read command line options */
1601 options = strchr(opt_user, '|');
1606 context = strchr(options, '@');
1612 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1619 option = (char)options[0];
1620 if ((option >= 0) && (option <= '9'))
1626 play_announcement = 0;
1628 badoption[0] = option;
1629 badoption[1] = '\0';
1630 tmpoptions=badoption;
1631 if (option_verbose > 2)
1632 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1638 /* End command line options */
1640 if (chan->_state != AST_STATE_UP)
1641 res = ast_answer(chan);
1643 if( opt_user && !ast_strlen_zero(opt_user))
1644 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1646 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1648 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1650 /* Check for password */
1651 ast_mutex_lock(&agentlock);
1654 if (!strcmp(p->agent, user) && !p->pending)
1655 strncpy(xpass, p->password, sizeof(xpass) - 1);
1658 ast_mutex_unlock(&agentlock);
1660 if (!ast_strlen_zero(xpass))
1661 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1665 errmsg = "agent-incorrect";
1668 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1671 /* Check again for accuracy */
1672 ast_mutex_lock(&agentlock);
1675 ast_mutex_lock(&p->lock);
1676 if (!strcmp(p->agent, user) &&
1677 !strcmp(p->password, pass) && !p->pending) {
1678 login_state = 1; /* Successful Login */
1679 /* Set Channel Specific Agent Overides */
1680 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1681 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1683 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1687 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1688 if (option_verbose > 2)
1689 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1691 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1692 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1693 if (p->autologoff < 0)
1695 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1696 if (option_verbose > 2)
1697 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1699 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1700 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1701 if (p->wrapuptime < 0)
1703 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1704 if (option_verbose > 2)
1705 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1707 /* End Channel Specific Agent Overides */
1709 char last_loginchan[80] = "";
1711 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1714 char tmpchan[AST_MAX_BUF] = "";
1716 /* Retrieve login chan */
1719 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1722 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1723 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1727 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1731 ast_log(LOG_WARNING, "Extension '%s@%s' is not valid for automatic login of agent '%s'\n", tmpchan, context && !ast_strlen_zero(context) ? context : "default", p->agent);
1732 res = ast_streamfile(chan, "invalid", chan->language);
1734 res = ast_waitstream(chan, AST_DIGIT_ANY);
1747 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1748 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1750 ast_copy_string(last_loginchan, p->loginchan, sizeof(last_loginchan));
1751 ast_copy_string(p->loginchan, tmpchan, sizeof(p->loginchan));
1753 p->acknowledged = 0;
1754 if (ast_strlen_zero(p->loginchan)) {
1756 filename = "agent-loggedoff";
1757 set_agentbycallerid(p);
1759 if (chan->cid.cid_num) {
1760 ast_copy_string(p->logincallerid, chan->cid.cid_num, sizeof(p->logincallerid));
1761 set_agentbycallerid(p);
1763 p->logincallerid[0] = '\0';
1766 if(update_cdr && chan->cdr)
1767 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1771 p->loginchan[0] = '\0';
1772 p->logincallerid[0] = '\0';
1773 p->acknowledged = 0;
1775 ast_mutex_unlock(&p->lock);
1776 ast_mutex_unlock(&agentlock);
1777 if( !res && play_announcement==1 )
1778 res = ast_streamfile(chan, filename, chan->language);
1780 ast_waitstream(chan, "");
1781 ast_mutex_lock(&agentlock);
1782 ast_mutex_lock(&p->lock);
1784 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1786 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1789 res = ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1791 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1793 /* Check once more just in case */
1796 if (callbackmode && !res) {
1797 /* Just say goodbye and be done with it */
1798 if (!ast_strlen_zero(p->loginchan)) {
1799 if (p->loginstart == 0)
1800 time(&p->loginstart);
1801 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1805 p->agent, p->loginchan, chan->uniqueid);
1806 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1807 if (option_verbose > 1)
1808 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1809 ast_device_state_changed("Agent/%s", p->agent);
1811 logintime = time(NULL) - p->loginstart;
1813 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1816 "Logintime: %ld\r\n"
1818 p->agent, last_loginchan, logintime, chan->uniqueid);
1819 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1820 if (option_verbose > 1)
1821 ast_verbose(VERBOSE_PREFIX_2 "Callback Agent '%s' logged out\n", p->agent);
1822 ast_device_state_changed("Agent/%s", p->agent);
1824 ast_mutex_unlock(&agentlock);
1826 res = ast_safe_sleep(chan, 500);
1827 ast_mutex_unlock(&p->lock);
1828 if (persistent_agents)
1831 #ifdef HONOR_MUSIC_CLASS
1832 /* check if the moh class was changed with setmusiconhold */
1833 if (*(chan->musicclass))
1834 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1836 ast_moh_start(chan, p->moh);
1837 if (p->loginstart == 0)
1838 time(&p->loginstart);
1839 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1843 p->agent, chan->name, chan->uniqueid);
1844 if (update_cdr && chan->cdr)
1845 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1846 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1847 if (option_verbose > 1)
1848 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1849 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1850 /* Login this channel and wait for it to
1856 check_availability(p, 0);
1857 ast_mutex_unlock(&p->lock);
1858 ast_mutex_unlock(&agentlock);
1859 ast_device_state_changed("Agent/%s", p->agent);
1861 ast_mutex_lock(&p->lock);
1862 if (p->chan != chan)
1864 ast_mutex_unlock(&p->lock);
1865 /* Yield here so other interested threads can kick in. */
1870 ast_mutex_lock(&agentlock);
1871 ast_mutex_lock(&p->lock);
1872 if (p->lastdisc.tv_sec) {
1873 gettimeofday(&tv, NULL);
1874 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1875 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1877 ast_log(LOG_DEBUG, "Wrapup time for %s expired!\n", p->agent);
1878 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1882 check_availability(p, 0);
1885 ast_mutex_unlock(&p->lock);
1886 ast_mutex_unlock(&agentlock);
1887 /* Synchronize channel ownership between call to agent and itself. */
1888 ast_mutex_lock( &p->app_lock );
1889 ast_mutex_lock(&p->lock);
1890 p->owning_app = pthread_self();
1891 ast_mutex_unlock(&p->lock);
1893 res = agent_ack_sleep(p);
1895 res = ast_safe_sleep_conditional( chan, 1000,
1896 agent_cont_sleep, p );
1897 ast_mutex_unlock( &p->app_lock );
1898 if ((p->ackcall > 1) && (res == 1)) {
1899 ast_mutex_lock(&agentlock);
1900 ast_mutex_lock(&p->lock);
1901 check_availability(p, 0);
1902 ast_mutex_unlock(&p->lock);
1903 ast_mutex_unlock(&agentlock);
1908 ast_mutex_lock(&p->lock);
1909 if (res && p->owner)
1910 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1911 /* Log us off if appropriate */
1912 if (p->chan == chan)
1914 p->acknowledged = 0;
1915 logintime = time(NULL) - p->loginstart;
1917 ast_mutex_unlock(&p->lock);
1918 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1920 "Logintime: %ld\r\n"
1922 p->agent, logintime, chan->uniqueid);
1923 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1924 if (option_verbose > 1)
1925 ast_verbose(VERBOSE_PREFIX_2 "Agent '%s' logged out\n", p->agent);
1926 /* If there is no owner, go ahead and kill it now */
1927 ast_device_state_changed("Agent/%s", p->agent);
1928 if (p->dead && !p->owner) {
1929 ast_mutex_destroy(&p->lock);
1930 ast_mutex_destroy(&p->app_lock);
1935 ast_mutex_unlock(&p->lock);
1940 ast_mutex_unlock(&p->lock);
1941 errmsg = "agent-alreadyon";
1946 ast_mutex_unlock(&p->lock);
1950 ast_mutex_unlock(&agentlock);
1952 if (!res && (max_login_tries==0 || tries < max_login_tries))
1953 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1956 LOCAL_USER_REMOVE(u);
1958 res = ast_safe_sleep(chan, 500);
1960 /* AgentLogin() exit */
1961 if (!callbackmode) {
1964 /* AgentCallbackLogin() exit*/
1967 if (login_state > 0) {
1968 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1969 if (login_state==1) {
1970 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1971 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1974 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1978 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1980 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1982 /* Do we need to play agent-goodbye now that we will be hanging up? */
1983 if (play_announcement==1) {
1985 res = ast_safe_sleep(chan, 1000);
1986 res = ast_streamfile(chan, agent_goodbye, chan->language);
1988 res = ast_waitstream(chan, "");
1990 res = ast_safe_sleep(chan, 1000);
1993 /* We should never get here if next priority exists when in callbackmode */
1997 static int login_exec(struct ast_channel *chan, void *data)
1999 return __login_exec(chan, data, 0);
2002 static int callback_exec(struct ast_channel *chan, void *data)
2004 return __login_exec(chan, data, 1);
2007 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
2009 int exitifnoagentid = 0;
2011 int changeoutgoing = 0;
2013 char agent[AST_MAX_AGENT], *tmp;
2016 if (strchr(data, 'd'))
2017 exitifnoagentid = 1;
2018 if (strchr(data, 'n'))
2020 if (strchr(data, 'c'))
2023 if (chan->cid.cid_num) {
2024 char agentvar[AST_MAX_BUF];
2025 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
2026 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
2027 struct agent_pvt *p = agents;
2028 strncpy(agent, tmp, sizeof(agent) - 1);
2029 ast_mutex_lock(&agentlock);
2031 if (!strcasecmp(p->agent, tmp)) {
2032 if (changeoutgoing) snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
2033 __agent_start_monitoring(chan, p, 1);
2038 ast_mutex_unlock(&agentlock);
2043 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);
2048 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");
2050 /* check if there is n + 101 priority */
2052 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
2053 chan->priority+=100;
2054 if (option_verbose > 2)
2055 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
2057 else if (exitifnoagentid)
2063 /* Dump AgentCallbackLogin agents to the database for persistence
2066 static void dump_agents(void)
2068 struct agent_pvt *cur_agent = NULL;
2071 for (cur_agent = agents; cur_agent; cur_agent = cur_agent->next) {
2072 if (cur_agent->chan)
2075 if (!ast_strlen_zero(cur_agent->loginchan)) {
2076 snprintf(buf, sizeof(buf), "%s;%s", cur_agent->loginchan, cur_agent->logincallerid);
2077 if (ast_db_put(pa_family, cur_agent->agent, buf))
2078 ast_log(LOG_WARNING, "failed to create persistent entry!\n");
2079 else if (option_debug)
2080 ast_log(LOG_DEBUG, "Saved Agent: %s on %s\n", cur_agent->agent, cur_agent->loginchan);
2082 /* Delete - no agent or there is an error */
2083 ast_db_del(pa_family, cur_agent->agent);
2088 /* Reload the persistent agents from astdb */
2089 static void reload_agents(void)
2092 struct ast_db_entry *db_tree;
2093 struct ast_db_entry *entry;
2094 struct agent_pvt *cur_agent;
2095 char agent_data[256];
2098 char *agent_callerid;
2100 db_tree = ast_db_gettree(pa_family, NULL);
2102 ast_mutex_lock(&agentlock);
2103 for (entry = db_tree; entry; entry = entry->next) {
2104 agent_num = entry->key + strlen(pa_family) + 2;
2107 ast_mutex_lock(&cur_agent->lock);
2108 if (strcmp(agent_num, cur_agent->agent) == 0)
2110 ast_mutex_unlock(&cur_agent->lock);
2111 cur_agent = cur_agent->next;
2114 ast_db_del(pa_family, agent_num);
2117 ast_mutex_unlock(&cur_agent->lock);
2118 if (!ast_db_get(pa_family, agent_num, agent_data, sizeof(agent_data)-1)) {
2120 ast_log(LOG_DEBUG, "Reload Agent: %s on %s\n", cur_agent->agent, agent_data);
2122 agent_chan = strsep(&parse, ";");
2123 agent_callerid = strsep(&parse, ";");
2124 ast_copy_string(cur_agent->loginchan, agent_chan, sizeof(cur_agent->loginchan));
2125 if (agent_callerid) {
2126 ast_copy_string(cur_agent->logincallerid, agent_callerid, sizeof(cur_agent->logincallerid));
2127 set_agentbycallerid(cur_agent);
2129 cur_agent->logincallerid[0] = '\0';
2130 if (cur_agent->loginstart == 0)
2131 time(&cur_agent->loginstart);
2132 ast_device_state_changed("Agent/%s", cur_agent->agent);
2135 ast_mutex_unlock(&agentlock);
2137 ast_log(LOG_NOTICE, "Agents sucessfully reloaded from database.\n");
2138 ast_db_freetree(db_tree);
2143 /*--- agent_devicestate: Part of PBX channel interface ---*/
2144 static int agent_devicestate(void *data)
2146 struct agent_pvt *p;
2148 ast_group_t groupmatch;
2151 int res = AST_DEVICE_INVALID;
2154 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2155 groupmatch = (1 << groupoff);
2156 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupoff) == 1)) {
2157 groupmatch = (1 << groupoff);
2163 /* Check actual logged in agents first */
2164 ast_mutex_lock(&agentlock);
2167 ast_mutex_lock(&p->lock);
2168 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
2170 if (res != AST_DEVICE_INUSE)
2171 res = AST_DEVICE_BUSY;
2173 if (res == AST_DEVICE_BUSY)
2174 res = AST_DEVICE_INUSE;
2175 if (p->chan || !ast_strlen_zero(p->loginchan)) {
2176 if (res == AST_DEVICE_INVALID)
2177 res = AST_DEVICE_UNKNOWN;
2178 } else if (res == AST_DEVICE_INVALID)
2179 res = AST_DEVICE_UNAVAILABLE;
2181 if (!strcmp(data, p->agent)) {
2182 ast_mutex_unlock(&p->lock);
2186 ast_mutex_unlock(&p->lock);
2189 ast_mutex_unlock(&agentlock);
2193 /*--- load_module: Initialize channel module ---*/
2196 /* Make sure we can register our agent channel type */
2197 if (ast_channel_register(&agent_tech)) {
2198 ast_log(LOG_ERROR, "Unable to register channel class %s\n", channeltype);
2201 /* Dialplan applications */
2202 ast_register_application(app, login_exec, synopsis, descrip);
2203 ast_register_application(app2, callback_exec, synopsis2, descrip2);
2204 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
2205 /* Manager command */
2206 ast_manager_register2("Agents", EVENT_FLAG_AGENT, action_agents, "Lists agents and their status", mandescr_agents);
2207 /* CLI Application */
2208 ast_cli_register(&cli_show_agents);
2209 ast_cli_register(&cli_agent_logoff);
2210 /* Read in the config */
2211 read_agent_config();
2212 if (persistent_agents)
2219 read_agent_config();
2220 if (persistent_agents)
2227 struct agent_pvt *p;
2228 /* First, take us out of the channel loop */
2229 /* Unregister CLI application */
2230 ast_cli_unregister(&cli_show_agents);
2231 ast_cli_unregister(&cli_agent_logoff);
2232 /* Unregister dialplan applications */
2233 ast_unregister_application(app);
2234 ast_unregister_application(app2);
2235 ast_unregister_application(app3);
2236 /* Unregister manager command */
2237 ast_manager_unregister("Agents");
2238 /* Unregister channel */
2239 ast_channel_unregister(&agent_tech);
2240 if (!ast_mutex_lock(&agentlock)) {
2241 /* Hangup all interfaces if they have an owner */
2245 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
2249 ast_mutex_unlock(&agentlock);
2251 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
2264 return ASTERISK_GPL_KEY;
2269 return (char *) desc;