2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Session Initiation Protocol
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
16 #include <asterisk/lock.h>
17 #include <asterisk/channel.h>
18 #include <asterisk/channel_pvt.h>
19 #include <asterisk/config.h>
20 #include <asterisk/logger.h>
21 #include <asterisk/module.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/options.h>
24 #include <asterisk/lock.h>
25 #include <asterisk/sched.h>
26 #include <asterisk/io.h>
27 #include <asterisk/rtp.h>
28 #include <asterisk/acl.h>
29 #include <asterisk/callerid.h>
30 #include <asterisk/file.h>
31 #include <asterisk/cli.h>
32 #include <asterisk/app.h>
33 #include <asterisk/musiconhold.h>
34 #include <asterisk/manager.h>
35 #include <asterisk/features.h>
36 #include <asterisk/utils.h>
37 #include <sys/socket.h>
43 #include <arpa/inet.h>
44 #include <sys/signal.h>
46 static char *desc = "Agent Proxy Channel";
47 static char *type = "Agent";
48 static char *tdesc = "Call Agent Proxy Channel";
49 static char *config = "agents.conf";
51 static char *app = "AgentLogin";
52 static char *app2 = "AgentCallbackLogin";
53 static char *app3 = "AgentMonitorOutgoing";
55 static char *synopsis = "Call agent login";
56 static char *synopsis2 = "Call agent callback login";
57 static char *synopsis3 = "Record agent's outgoing call";
59 static char *descrip =
60 " AgentLogin([AgentNo][|options]):\n"
61 "Asks the agent to login to the system. Always returns -1. While\n"
62 "logged in, the agent can receive calls and will hear a 'beep'\n"
63 "when a new call comes in. The agent can dump the call by pressing\n"
65 "The option string may contain zero or more of the following characters:\n"
66 " 's' -- silent login - do not announce the login ok segment\n";
68 static char *descrip2 =
69 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
70 "Asks the agent to login to the system with callback. Always returns -1.\n"
71 "The agent's callback extension is called (optionally with the specified\n"
74 static char *descrip3 =
75 " AgentMonitorOutgoing([options]):\n"
76 "Tries to figure out the id of the agent who is placing outgoing call based on comparision of the callerid of the current interface and the global variable placed by the AgentCallbackLogin application. That's why it should be used only with the AgentCallbackLogin app. Uses the monitoring functions in chan_agent instead of Monitor application. That have to be configured in the agents.conf file. Normally the app returns 0 unless the options are passed. Also if the callerid or the agentid are not specified it'll look for n+101 priority. The options are:\n"
77 " 'd' - make the app return -1 if there is an error condition and there is no extension n+101\n"
78 " 'n' - don't generate the warnings when there is no callerid or the agentid is not known. It's handy if you want to have one context for agent and non-agent calls.\n";
80 static char moh[80] = "default";
82 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
83 #define AST_MAX_BUF 256
85 static int capability = -1;
87 static unsigned int group;
88 static int autologoff;
89 static int wrapuptime;
93 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
95 /* Protect the interface list (of sip_pvt's) */
96 AST_MUTEX_DEFINE_STATIC(agentlock);
98 static int recordagentcalls = 0;
99 static char recordformat[AST_MAX_BUF] = "";
100 static char recordformatext[AST_MAX_BUF] = "";
101 static int createlink = 0;
102 static char urlprefix[AST_MAX_BUF] = "";
103 static char savecallsin[AST_MAX_BUF] = "";
104 static int updatecdr = 0;
105 static char beep[AST_MAX_BUF] = "beep";
107 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
109 static struct agent_pvt {
110 ast_mutex_t lock; /* Channel private lock */
111 int dead; /* Poised for destruction? */
112 int pending; /* Not a real agent -- just pending a match */
113 int abouttograb; /* About to grab */
114 int autologoff; /* Auto timeout time */
115 int ackcall; /* ackcall */
116 time_t loginstart; /* When agent first logged in (0 when logged off) */
117 time_t start; /* When call started */
118 struct timeval lastdisc; /* When last disconnected */
119 int wrapuptime; /* Wrapup time in ms */
120 unsigned int group; /* Group memberships */
121 int acknowledged; /* Acknowledged */
122 char moh[80]; /* Which music on hold */
123 char agent[AST_MAX_AGENT]; /* Agent ID */
124 char password[AST_MAX_AGENT]; /* Password for Agent login */
125 char name[AST_MAX_AGENT];
126 ast_mutex_t app_lock; /* Synchronization between owning applications */
127 volatile pthread_t owning_app; /* Owning application thread id */
128 volatile int app_sleep_cond; /* Sleep condition for the login app */
129 struct ast_channel *owner; /* Agent */
131 struct ast_channel *chan; /* Channel we use */
132 struct agent_pvt *next; /* Agent */
135 #define CHECK_FORMATS(ast, p) do { \
137 if (ast->nativeformats != p->chan->nativeformats) { \
138 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
139 /* Native formats changed, reset things */ \
140 ast->nativeformats = p->chan->nativeformats; \
141 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
142 ast_set_read_format(ast, ast->readformat); \
143 ast_set_write_format(ast, ast->writeformat); \
145 if (p->chan->readformat != ast->pvt->rawreadformat) \
146 ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
147 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
148 ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
152 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
153 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
154 totally impractical combinations XXX */
156 #define CLEANUP(ast, p) do { \
159 for (x=0;x<AST_MAX_FDS;x++) {\
160 if (x != AST_MAX_FDS - 2) \
161 ast->fds[x] = p->chan->fds[x]; \
163 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
168 static void agent_unlink(struct agent_pvt *agent)
170 struct agent_pvt *p, *prev;
176 prev->next = agent->next;
178 agents = agent->next;
186 static struct agent_pvt *add_agent(char *agent, int pending)
188 char tmp[AST_MAX_BUF] = "";
189 char *password=NULL, *name=NULL;
190 struct agent_pvt *p, *prev;
192 strncpy(tmp, agent, sizeof(tmp) - 1);
193 if ((password = strchr(tmp, ','))) {
196 while (*password < 33) password++;
198 if (password && (name = strchr(password, ','))) {
201 while (*name < 33) name++;
206 if (!pending && !strcmp(p->agent, tmp))
212 p = malloc(sizeof(struct agent_pvt));
214 memset(p, 0, sizeof(struct agent_pvt));
215 strncpy(p->agent, tmp, sizeof(p->agent) -1);
216 ast_mutex_init(&p->lock);
217 ast_mutex_init(&p->app_lock);
218 p->owning_app = (pthread_t) -1;
219 p->app_sleep_cond = 1;
221 p->pending = pending;
232 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
233 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
234 strncpy(p->moh, moh, sizeof(p->moh) - 1);
235 p->ackcall = ackcall;
236 p->autologoff = autologoff;
237 p->wrapuptime = wrapuptime;
245 static int agent_cleanup(struct agent_pvt *p)
247 struct ast_channel *chan = p->owner;
249 chan->pvt->pvt = NULL;
250 p->app_sleep_cond = 1;
251 /* Release ownership of the agent to other threads (presumably running the login app). */
252 ast_mutex_unlock(&p->app_lock);
254 ast_channel_free(chan);
256 ast_mutex_destroy(&p->lock);
257 ast_mutex_destroy(&p->app_lock);
263 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
265 static int agent_answer(struct ast_channel *ast)
267 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
271 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
273 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
274 char filename[AST_MAX_BUF];
279 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
280 /* substitute . for - */
281 if ((pointer = strchr(filename, '.')))
283 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
284 ast_monitor_start(ast, recordformat, tmp, needlock);
285 ast_monitor_setjoinfiles(ast, 1);
286 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
288 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
291 ast->cdr = ast_cdr_alloc();
292 ast_cdr_setuserfield(ast, tmp2);
295 ast_log(LOG_ERROR, "Recording already started on that call.\n");
299 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
301 return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
304 static struct ast_frame *agent_read(struct ast_channel *ast)
306 struct agent_pvt *p = ast->pvt->pvt;
307 struct ast_frame *f = NULL;
308 static struct ast_frame null_frame = { AST_FRAME_NULL, };
309 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
310 ast_mutex_lock(&p->lock);
311 CHECK_FORMATS(ast, p);
313 p->chan->exception = ast->exception;
314 if (ast->fdno == AST_MAX_FDS - 3)
315 p->chan->fdno = AST_MAX_FDS - 2;
317 p->chan->fdno = ast->fdno;
318 f = ast_read(p->chan);
322 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
324 /* Note that we don't hangup if it's not a callback because Asterisk will do it
325 for us when the PBX instance that called login finishes */
326 if (!ast_strlen_zero(p->loginchan))
332 if (f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
335 if (option_verbose > 2)
336 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
337 /* Don't pass answer along */
346 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
347 if (!p->acknowledged) {
348 if (option_verbose > 2)
349 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
355 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
356 /* * terminates call */
361 ast_mutex_unlock(&p->lock);
362 if (recordagentcalls && f == &answer_frame)
363 agent_start_monitoring(ast,0);
367 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
369 struct agent_pvt *p = ast->pvt->pvt;
371 CHECK_FORMATS(ast, p);
372 ast_mutex_lock(&p->lock);
374 if ((f->frametype != AST_FRAME_VOICE) ||
375 (f->subclass == p->chan->writeformat)) {
376 res = ast_write(p->chan, f);
378 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
384 ast_mutex_unlock(&p->lock);
388 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
390 struct agent_pvt *p = newchan->pvt->pvt;
391 ast_mutex_lock(&p->lock);
392 if (p->owner != oldchan) {
393 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
394 ast_mutex_unlock(&p->lock);
398 ast_mutex_unlock(&p->lock);
402 static int agent_indicate(struct ast_channel *ast, int condition)
404 struct agent_pvt *p = ast->pvt->pvt;
406 ast_mutex_lock(&p->lock);
408 res = ast_indicate(p->chan, condition);
411 ast_mutex_unlock(&p->lock);
415 static int agent_digit(struct ast_channel *ast, char digit)
417 struct agent_pvt *p = ast->pvt->pvt;
419 ast_mutex_lock(&p->lock);
421 res = p->chan->pvt->send_digit(p->chan, digit);
424 ast_mutex_unlock(&p->lock);
428 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
430 struct agent_pvt *p = ast->pvt->pvt;
432 ast_mutex_lock(&p->lock);
436 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
437 ast_setstate(ast, AST_STATE_DIALING);
440 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
443 ast_mutex_unlock(&p->lock);
445 } else if (!ast_strlen_zero(p->loginchan)) {
447 /* Call on this agent */
448 if (option_verbose > 2)
449 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
450 if (p->chan->callerid)
451 free(p->chan->callerid);
453 p->chan->callerid = strdup(ast->callerid);
455 p->chan->callerid = NULL;
456 res = ast_call(p->chan, p->loginchan, 0);
458 ast_mutex_unlock(&p->lock);
461 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
462 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
463 res = ast_streamfile(p->chan, beep, p->chan->language);
464 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
466 res = ast_waitstream(p->chan, "");
467 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
470 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
471 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
473 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
480 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
481 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
483 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
487 /* Call is immediately up, or might need ack */
489 ast_setstate(ast, AST_STATE_RINGING);
491 ast_setstate(ast, AST_STATE_UP);
492 if (recordagentcalls)
493 agent_start_monitoring(ast,0);
499 ast_mutex_unlock(&p->lock);
503 static int agent_hangup(struct ast_channel *ast)
505 struct agent_pvt *p = ast->pvt->pvt;
507 ast_mutex_lock(&p->lock);
509 ast->pvt->pvt = NULL;
510 p->app_sleep_cond = 1;
512 if (p->start && (ast->_state != AST_STATE_UP))
513 howlong = time(NULL) - p->start;
516 /* If they're dead, go ahead and hang up on the agent now */
517 if (!ast_strlen_zero(p->loginchan)) {
518 /* Store last disconnect time */
520 gettimeofday(&p->lastdisc, NULL);
521 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
522 if (p->lastdisc.tv_usec >= 1000000) {
523 p->lastdisc.tv_usec -= 1000000;
524 p->lastdisc.tv_sec++;
526 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
528 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
530 /* Recognize the hangup and pass it along immediately */
534 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
535 if (howlong && p->autologoff && (howlong > p->autologoff)) {
536 char agent[AST_MAX_AGENT] = "";
537 long logintime = time(NULL) - p->loginstart;
539 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
540 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
544 "Reason: Autologoff\r\n"
546 p->agent, p->loginchan, logintime, ast->uniqueid);
547 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
548 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
549 p->loginchan[0] = '\0';
551 } else if (p->dead) {
552 ast_mutex_lock(&p->chan->lock);
553 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
554 ast_mutex_unlock(&p->chan->lock);
556 ast_mutex_lock(&p->chan->lock);
557 ast_moh_start(p->chan, p->moh);
558 ast_mutex_unlock(&p->chan->lock);
562 ast_mutex_unlock(&p->lock);
563 /* Release ownership of the agent to other threads (presumably running the login app). */
564 ast_mutex_unlock(&p->app_lock);
565 } else if (p->dead) {
566 /* Go ahead and lose it */
567 ast_mutex_unlock(&p->lock);
568 /* Release ownership of the agent to other threads (presumably running the login app). */
569 ast_mutex_unlock(&p->app_lock);
571 ast_mutex_unlock(&p->lock);
572 /* Release ownership of the agent to other threads (presumably running the login app). */
573 ast_mutex_unlock(&p->app_lock);
576 ast_mutex_unlock(&p->lock);
579 ast_mutex_lock(&agentlock);
581 ast_mutex_unlock(&agentlock);
583 if (p->abouttograb) {
584 /* Let the "about to grab" thread know this isn't valid anymore, and let it
587 } else if (p->dead) {
588 ast_mutex_destroy(&p->lock);
589 ast_mutex_destroy(&p->app_lock);
593 /* Not dead -- check availability now */
594 ast_mutex_lock(&p->lock);
595 /* Store last disconnect time */
596 gettimeofday(&p->lastdisc, NULL);
597 ast_mutex_unlock(&p->lock);
599 /* Release ownership of the agent to other threads (presumably running the login app). */
600 ast_mutex_unlock(&p->app_lock);
605 static int agent_cont_sleep( void *data )
611 p = (struct agent_pvt *)data;
613 ast_mutex_lock(&p->lock);
614 res = p->app_sleep_cond;
615 if (p->lastdisc.tv_sec) {
616 gettimeofday(&tv, NULL);
617 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
618 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
621 ast_mutex_unlock(&p->lock);
624 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
629 static int agent_ack_sleep( void *data )
636 /* Wait a second and look for something */
638 p = (struct agent_pvt *)data;
641 to = ast_waitfor(p->chan, to);
650 f = ast_read(p->chan);
655 if (f->frametype == AST_FRAME_DTMF)
660 ast_mutex_lock(&p->lock);
661 if (!p->app_sleep_cond) {
662 ast_mutex_unlock(&p->lock);
665 } else if (res == '#') {
666 ast_mutex_unlock(&p->lock);
670 ast_mutex_unlock(&p->lock);
678 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
680 struct ast_channel *tmp;
681 struct ast_frame null_frame = { AST_FRAME_NULL };
684 ast_log(LOG_WARNING, "No channel? :(\n");
688 tmp = ast_channel_alloc(0);
691 tmp->nativeformats = p->chan->nativeformats;
692 tmp->writeformat = p->chan->writeformat;
693 tmp->pvt->rawwriteformat = p->chan->writeformat;
694 tmp->readformat = p->chan->readformat;
695 tmp->pvt->rawreadformat = p->chan->readformat;
696 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
697 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
698 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
700 tmp->nativeformats = AST_FORMAT_SLINEAR;
701 tmp->writeformat = AST_FORMAT_SLINEAR;
702 tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
703 tmp->readformat = AST_FORMAT_SLINEAR;
704 tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
707 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
709 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
711 ast_setstate(tmp, state);
713 tmp->pvt->send_digit = agent_digit;
714 tmp->pvt->call = agent_call;
715 tmp->pvt->hangup = agent_hangup;
716 tmp->pvt->answer = agent_answer;
717 tmp->pvt->read = agent_read;
718 tmp->pvt->write = agent_write;
719 tmp->pvt->exception = agent_read;
720 tmp->pvt->indicate = agent_indicate;
721 tmp->pvt->fixup = agent_fixup;
723 ast_mutex_lock(&usecnt_lock);
725 ast_mutex_unlock(&usecnt_lock);
726 ast_update_use_count();
728 /* Wake up and wait for other applications (by definition the login app)
729 * to release this channel). Takes ownership of the agent channel
730 * to this thread only.
731 * For signalling the other thread, ast_queue_frame is used until we
732 * can safely use signals for this purpose. The pselect() needs to be
733 * implemented in the kernel for this.
735 p->app_sleep_cond = 0;
736 if( ast_mutex_trylock(&p->app_lock) )
739 ast_queue_frame(p->chan, &null_frame);
740 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
741 ast_mutex_lock(&p->app_lock);
742 ast_mutex_lock(&p->lock);
746 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
748 tmp->pvt->pvt = NULL;
749 p->app_sleep_cond = 1;
750 ast_channel_free( tmp );
751 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
752 ast_mutex_unlock(&p->app_lock);
756 p->owning_app = pthread_self();
757 /* After the above step, there should not be any blockers. */
759 if (p->chan->blocking) {
760 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
763 ast_moh_stop(p->chan);
766 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
771 static int read_agent_config(void)
773 struct ast_config *cfg;
774 struct ast_variable *v;
775 struct agent_pvt *p, *pl, *pn;
780 cfg = ast_load(config);
782 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
785 ast_mutex_lock(&agentlock);
791 strncpy(moh, "default", sizeof(moh) - 1);
792 /* set the default recording values */
793 recordagentcalls = 0;
795 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
796 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
798 savecallsin[0] = '\0';
800 v = ast_variable_browse(cfg, "agents");
802 /* Create the interface list */
803 if (!strcasecmp(v->name, "agent")) {
804 add_agent(v->value, 0);
805 } else if (!strcasecmp(v->name, "group")) {
806 group = ast_get_group(v->value);
807 } else if (!strcasecmp(v->name, "autologoff")) {
808 autologoff = atoi(v->value);
811 } else if (!strcasecmp(v->name, "ackcall")) {
812 if (!strcasecmp(v->value, "always"))
814 else if (ast_true(v->value))
818 } else if (!strcasecmp(v->name, "wrapuptime")) {
819 wrapuptime = atoi(v->value);
822 } else if (!strcasecmp(v->name, "musiconhold")) {
823 strncpy(moh, v->value, sizeof(moh) - 1);
824 } else if (!strcasecmp(v->name, "updatecdr")) {
825 updatecdr = ast_true(v->value);
826 } else if (!strcasecmp(v->name, "recordagentcalls")) {
827 recordagentcalls = ast_true(v->value);
828 } else if (!strcasecmp(v->name, "createlink")) {
829 createlink = ast_true(v->value);
830 } else if (!strcasecmp(v->name, "recordformat")) {
831 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
832 if (!strcasecmp(v->value, "wav49"))
833 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
835 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
836 } else if (!strcasecmp(v->name, "urlprefix")) {
837 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
838 if (urlprefix[strlen(urlprefix) - 1] != '/')
839 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
840 } else if (!strcasecmp(v->name, "savecallsin")) {
841 if (v->value[0] == '/')
842 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
844 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
845 if (savecallsin[strlen(savecallsin) - 1] != '/')
846 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
847 } else if (!strcasecmp(v->name, "custom_beep")) {
848 strncpy(beep, v->value, sizeof(beep) - 1);
862 /* Destroy if appropriate */
865 ast_mutex_destroy(&p->lock);
866 ast_mutex_destroy(&p->app_lock);
869 /* Cause them to hang up */
870 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
877 ast_mutex_unlock(&agentlock);
882 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
884 struct ast_channel *chan=NULL, *parent=NULL;
887 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
889 ast_mutex_lock(&agentlock);
892 if (p == newlyavailable) {
896 ast_mutex_lock(&p->lock);
897 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
898 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
899 /* We found a pending call, time to merge */
900 chan = agent_new(newlyavailable, AST_STATE_DOWN);
903 ast_mutex_unlock(&p->lock);
906 ast_mutex_unlock(&p->lock);
910 ast_mutex_unlock(&agentlock);
911 if (parent && chan) {
912 if (newlyavailable->ackcall > 1) {
913 /* Don't do beep here */
916 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
917 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
918 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
920 res = ast_waitstream(newlyavailable->chan, "");
921 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
925 /* Note -- parent may have disappeared */
926 if (p->abouttograb) {
927 newlyavailable->acknowledged = 1;
928 ast_setstate(parent, AST_STATE_UP);
929 ast_setstate(chan, AST_STATE_UP);
930 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
931 /* Go ahead and mark the channel as a zombie so that masquerade will
932 destroy it for us, and we need not call ast_hangup */
933 ast_mutex_lock(&parent->lock);
935 ast_channel_masquerade(parent, chan);
936 ast_mutex_unlock(&parent->lock);
939 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
940 agent_cleanup(newlyavailable);
943 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
944 agent_cleanup(newlyavailable);
950 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
954 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
956 ast_mutex_lock(&agentlock);
959 if (p == newlyavailable) {
963 ast_mutex_lock(&p->lock);
964 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
965 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
966 ast_mutex_unlock(&p->lock);
969 ast_mutex_unlock(&p->lock);
973 ast_mutex_unlock(&agentlock);
975 ast_mutex_unlock(&newlyavailable->lock);
976 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
977 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
978 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
980 res = ast_waitstream(newlyavailable->chan, "");
981 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
983 ast_mutex_lock(&newlyavailable->lock);
988 static struct ast_channel *agent_request(char *type, int format, void *data)
991 struct ast_channel *chan = NULL;
993 unsigned int groupmatch;
997 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
998 groupmatch = (1 << groupmatch);
999 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1000 groupmatch = (1 << groupmatch);
1006 /* Check actual logged in agents first */
1007 ast_mutex_lock(&agentlock);
1010 ast_mutex_lock(&p->lock);
1011 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1012 ast_strlen_zero(p->loginchan)) {
1015 if (!p->lastdisc.tv_sec) {
1016 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1017 if (!p->owner && p->chan) {
1019 chan = agent_new(p, AST_STATE_DOWN);
1022 ast_mutex_unlock(&p->lock);
1027 ast_mutex_unlock(&p->lock);
1033 ast_mutex_lock(&p->lock);
1034 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1035 if (p->chan || !ast_strlen_zero(p->loginchan))
1037 if (!p->lastdisc.tv_sec || (time(NULL) > p->lastdisc.tv_sec)) {
1038 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1039 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1040 if (!p->owner && p->chan) {
1041 /* Could still get a fixed agent */
1042 chan = agent_new(p, AST_STATE_DOWN);
1043 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1044 /* Adjustable agent */
1045 p->chan = ast_request("Local", format, p->loginchan);
1047 chan = agent_new(p, AST_STATE_DOWN);
1050 ast_mutex_unlock(&p->lock);
1055 ast_mutex_unlock(&p->lock);
1060 if (!chan && waitforagent) {
1061 /* No agent available -- but we're requesting to wait for one.
1062 Allocate a place holder */
1064 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1065 p = add_agent(data, 1);
1066 p->group = groupmatch;
1067 chan = agent_new(p, AST_STATE_DOWN);
1069 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1072 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1074 ast_mutex_unlock(&agentlock);
1078 static int powerof(unsigned int v)
1081 for (x=0;x<32;x++) {
1082 if (v & (1 << x)) return x;
1087 static int agents_show(int fd, int argc, char **argv)
1089 struct agent_pvt *p;
1090 char username[AST_MAX_BUF];
1091 char location[AST_MAX_BUF] = "";
1092 char talkingto[AST_MAX_BUF] = "";
1093 char moh[AST_MAX_BUF];
1096 return RESULT_SHOWUSAGE;
1097 ast_mutex_lock(&agentlock);
1100 ast_mutex_lock(&p->lock);
1103 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1105 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1107 if (!ast_strlen_zero(p->name))
1108 snprintf(username, sizeof(username), "(%s) ", p->name);
1112 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1113 if (p->owner && p->owner->bridge) {
1114 snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
1116 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1118 } else if (!ast_strlen_zero(p->loginchan)) {
1119 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1120 talkingto[0] = '\0';
1121 if (p->acknowledged)
1122 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1124 strncpy(location, "not logged in", sizeof(location) - 1);
1125 talkingto[0] = '\0';
1127 if (!ast_strlen_zero(p->moh))
1128 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1129 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1130 username, location, talkingto, moh);
1132 ast_mutex_unlock(&p->lock);
1135 ast_mutex_unlock(&agentlock);
1136 return RESULT_SUCCESS;
1139 static char show_agents_usage[] =
1140 "Usage: show agents\n"
1141 " Provides summary information on agents.\n";
1143 static struct ast_cli_entry cli_show_agents = {
1144 { "show", "agents", NULL }, agents_show,
1145 "Show status of agents", show_agents_usage, NULL };
1147 STANDARD_LOCAL_USER;
1150 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1154 struct agent_pvt *p;
1155 struct localuser *u;
1157 char user[AST_MAX_AGENT] = "";
1158 char pass[AST_MAX_AGENT];
1159 char agent[AST_MAX_AGENT] = "";
1160 char xpass[AST_MAX_AGENT] = "";
1163 char *opt_user = NULL;
1164 char *options = NULL;
1165 char *context = NULL;
1167 int play_announcement;
1168 char *filename = "agent-loginok";
1172 /* Parse the arguments XXX Check for failure XXX */
1173 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1176 options = strchr(opt_user, '|');
1181 context = strchr(options, '@');
1187 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1194 if (chan->_state != AST_STATE_UP)
1195 res = ast_answer(chan);
1197 if( opt_user && !ast_strlen_zero(opt_user))
1198 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1200 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1202 while (!res && (tries < 3)) {
1203 /* Check for password */
1204 ast_mutex_lock(&agentlock);
1207 if (!strcmp(p->agent, user) && !p->pending)
1208 strncpy(xpass, p->password, sizeof(xpass) - 1);
1211 ast_mutex_unlock(&agentlock);
1213 if (!ast_strlen_zero(xpass))
1214 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1218 errmsg = "agent-incorrect";
1221 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1224 /* Check again for accuracy */
1225 ast_mutex_lock(&agentlock);
1228 ast_mutex_lock(&p->lock);
1229 if (!strcmp(p->agent, user) &&
1230 !strcmp(p->password, pass) && !p->pending) {
1232 char last_loginchan[80] = "";
1234 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1237 char tmpchan[AST_MAX_BUF] = "";
1239 /* Retrieve login chan */
1242 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1245 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1246 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1250 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1254 res = ast_streamfile(chan, "invalid", chan->language);
1256 res = ast_waitstream(chan, AST_DIGIT_ANY);
1268 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1269 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1271 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1272 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1274 if (ast_strlen_zero(p->loginchan))
1275 filename = "agent-loggedoff";
1276 p->acknowledged = 0;
1277 /* store/clear the global variable that stores agentid based on the callerid */
1278 if (chan->callerid) {
1279 char agentvar[AST_MAX_BUF];
1280 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->callerid);
1281 if (ast_strlen_zero(p->loginchan))
1282 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1284 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1286 if(updatecdr && chan->cdr)
1287 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1291 p->loginchan[0] = '\0';
1292 p->acknowledged = 0;
1294 play_announcement = 1;
1296 if( strchr( options, 's' ) )
1297 play_announcement = 0;
1298 ast_mutex_unlock(&p->lock);
1299 ast_mutex_unlock(&agentlock);
1300 if( !res && play_announcement )
1301 res = ast_streamfile(chan, filename, chan->language);
1303 ast_waitstream(chan, "");
1304 ast_mutex_lock(&agentlock);
1305 ast_mutex_lock(&p->lock);
1307 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1309 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1312 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1314 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1316 /* Check once more just in case */
1319 if (callbackmode && !res) {
1320 /* Just say goodbye and be done with it */
1321 if (!ast_strlen_zero(p->loginchan)) {
1322 if (p->loginstart == 0)
1323 time(&p->loginstart);
1324 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1328 p->agent, p->loginchan, chan->uniqueid);
1329 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1330 if (option_verbose > 2)
1331 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1333 logintime = time(NULL) - p->loginstart;
1335 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1338 "Logintime: %ld\r\n"
1340 p->agent, last_loginchan, logintime, chan->uniqueid);
1341 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1342 if (option_verbose > 2)
1343 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged out\n", p->agent);
1345 ast_mutex_unlock(&agentlock);
1347 res = ast_safe_sleep(chan, 500);
1348 res = ast_streamfile(chan, "vm-goodbye", chan->language);
1350 res = ast_waitstream(chan, "");
1352 res = ast_safe_sleep(chan, 1000);
1353 ast_mutex_unlock(&p->lock);
1355 #ifdef HONOR_MUSIC_CLASS
1356 /* check if the moh class was changed with setmusiconhold */
1357 if (*(chan->musicclass))
1358 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1360 ast_moh_start(chan, p->moh);
1361 if (p->loginstart == 0)
1362 time(&p->loginstart);
1363 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1367 p->agent, chan->name, chan->uniqueid);
1368 if (updatecdr && chan->cdr)
1369 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1370 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1371 if (option_verbose > 2)
1372 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1373 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1374 /* Login this channel and wait for it to
1380 check_availability(p, 0);
1381 ast_mutex_unlock(&p->lock);
1382 ast_mutex_unlock(&agentlock);
1384 ast_mutex_lock(&p->lock);
1385 if (p->chan != chan)
1387 ast_mutex_unlock(&p->lock);
1388 /* Yield here so other interested threads can kick in. */
1393 ast_mutex_lock(&agentlock);
1394 ast_mutex_lock(&p->lock);
1395 if (p->lastdisc.tv_sec) {
1396 gettimeofday(&tv, NULL);
1397 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1398 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1399 ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1400 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1404 check_availability(p, 0);
1407 ast_mutex_unlock(&p->lock);
1408 ast_mutex_unlock(&agentlock);
1409 /* Synchronize channel ownership between call to agent and itself. */
1410 ast_mutex_lock( &p->app_lock );
1411 ast_mutex_lock(&p->lock);
1412 p->owning_app = pthread_self();
1413 ast_mutex_unlock(&p->lock);
1415 res = agent_ack_sleep(p);
1417 res = ast_safe_sleep_conditional( chan, 1000,
1418 agent_cont_sleep, p );
1419 ast_mutex_unlock( &p->app_lock );
1420 if ((p->ackcall > 1) && (res == 1)) {
1421 ast_mutex_lock(&agentlock);
1422 ast_mutex_lock(&p->lock);
1423 check_availability(p, 0);
1424 ast_mutex_unlock(&p->lock);
1425 ast_mutex_unlock(&agentlock);
1430 ast_mutex_lock(&p->lock);
1431 if (res && p->owner)
1432 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1433 /* Log us off if appropriate */
1434 if (p->chan == chan)
1436 p->acknowledged = 0;
1437 logintime = time(NULL) - p->loginstart;
1439 ast_mutex_unlock(&p->lock);
1440 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1442 "Logintime: %ld\r\n"
1444 p->agent, logintime, chan->uniqueid);
1445 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1446 if (option_verbose > 2)
1447 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1448 /* If there is no owner, go ahead and kill it now */
1449 if (p->dead && !p->owner) {
1450 ast_mutex_destroy(&p->lock);
1451 ast_mutex_destroy(&p->app_lock);
1456 ast_mutex_unlock(&p->lock);
1461 ast_mutex_unlock(&p->lock);
1462 errmsg = "agent-alreadyon";
1467 ast_mutex_unlock(&p->lock);
1471 ast_mutex_unlock(&agentlock);
1474 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1477 LOCAL_USER_REMOVE(u);
1482 static int login_exec(struct ast_channel *chan, void *data)
1484 return __login_exec(chan, data, 0);
1487 static int callback_exec(struct ast_channel *chan, void *data)
1489 return __login_exec(chan, data, 1);
1492 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1494 int exitifnoagentid = 0;
1497 char agent[AST_MAX_AGENT], *tmp;
1499 if (strchr(data, 'd'))
1500 exitifnoagentid = 1;
1501 if (strchr(data, 'n'))
1504 if (chan->callerid) {
1505 char agentvar[AST_MAX_BUF];
1506 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->callerid);
1507 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1508 struct agent_pvt *p = agents;
1509 strncpy(agent, tmp, sizeof(agent) - 1);
1510 ast_mutex_lock(&agentlock);
1512 if (!strcasecmp(p->agent, tmp)) {
1513 __agent_start_monitoring(chan, p, 1);
1518 ast_mutex_unlock(&agentlock);
1523 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);
1528 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");
1530 /* check if there is n + 101 priority */
1532 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
1533 chan->priority+=100;
1534 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1536 else if (exitifnoagentid)
1544 /* Make sure we can register our sip channel type */
1545 if (ast_channel_register(type, tdesc, capability, agent_request)) {
1546 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1549 ast_register_application(app, login_exec, synopsis, descrip);
1550 ast_register_application(app2, callback_exec, synopsis2, descrip2);
1551 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1552 ast_cli_register(&cli_show_agents);
1553 /* Read in the config */
1554 read_agent_config();
1560 read_agent_config();
1566 struct agent_pvt *p;
1567 /* First, take us out of the channel loop */
1568 ast_cli_unregister(&cli_show_agents);
1569 ast_unregister_application(app);
1570 ast_unregister_application(app2);
1571 ast_unregister_application(app3);
1572 ast_channel_unregister(type);
1573 if (!ast_mutex_lock(&agentlock)) {
1574 /* Hangup all interfaces if they have an owner */
1578 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1582 ast_mutex_unlock(&agentlock);
1584 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1593 ast_mutex_lock(&usecnt_lock);
1595 ast_mutex_unlock(&usecnt_lock);
1601 return ASTERISK_GPL_KEY;