2 * Asterisk -- A telephony toolkit for Linux.
4 * Implementation of Agents
6 * Copyright (C) 1999-2004, 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
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)) {
329 gettimeofday(&p->lastdisc, NULL);
330 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
331 if (p->lastdisc.tv_usec > 1000000) {
332 p->lastdisc.tv_usec -= 1000000;
333 p->lastdisc.tv_sec++;
335 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
342 if (f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
345 if (option_verbose > 2)
346 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
347 /* Don't pass answer along */
356 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
357 if (!p->acknowledged) {
358 if (option_verbose > 2)
359 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
365 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
366 /* * terminates call */
371 ast_mutex_unlock(&p->lock);
372 if (recordagentcalls && f == &answer_frame)
373 agent_start_monitoring(ast,0);
377 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
379 struct agent_pvt *p = ast->pvt->pvt;
381 CHECK_FORMATS(ast, p);
382 ast_mutex_lock(&p->lock);
384 if ((f->frametype != AST_FRAME_VOICE) ||
385 (f->subclass == p->chan->writeformat)) {
386 res = ast_write(p->chan, f);
388 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
394 ast_mutex_unlock(&p->lock);
398 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
400 struct agent_pvt *p = newchan->pvt->pvt;
401 ast_mutex_lock(&p->lock);
402 if (p->owner != oldchan) {
403 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
404 ast_mutex_unlock(&p->lock);
408 ast_mutex_unlock(&p->lock);
412 static int agent_indicate(struct ast_channel *ast, int condition)
414 struct agent_pvt *p = ast->pvt->pvt;
416 ast_mutex_lock(&p->lock);
418 res = ast_indicate(p->chan, condition);
421 ast_mutex_unlock(&p->lock);
425 static int agent_digit(struct ast_channel *ast, char digit)
427 struct agent_pvt *p = ast->pvt->pvt;
429 ast_mutex_lock(&p->lock);
431 res = p->chan->pvt->send_digit(p->chan, digit);
434 ast_mutex_unlock(&p->lock);
438 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
440 struct agent_pvt *p = ast->pvt->pvt;
442 ast_mutex_lock(&p->lock);
446 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
447 ast_setstate(ast, AST_STATE_DIALING);
450 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
453 ast_mutex_unlock(&p->lock);
455 } else if (!ast_strlen_zero(p->loginchan)) {
457 /* Call on this agent */
458 if (option_verbose > 2)
459 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
460 if (p->chan->callerid)
461 free(p->chan->callerid);
463 p->chan->callerid = strdup(ast->callerid);
465 p->chan->callerid = NULL;
466 res = ast_call(p->chan, p->loginchan, 0);
468 ast_mutex_unlock(&p->lock);
471 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
472 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
473 res = ast_streamfile(p->chan, beep, p->chan->language);
474 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
476 res = ast_waitstream(p->chan, "");
477 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
480 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
481 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
483 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
490 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
491 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
493 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
497 /* Call is immediately up, or might need ack */
499 ast_setstate(ast, AST_STATE_RINGING);
501 ast_setstate(ast, AST_STATE_UP);
502 if (recordagentcalls)
503 agent_start_monitoring(ast,0);
509 ast_mutex_unlock(&p->lock);
513 static int agent_hangup(struct ast_channel *ast)
515 struct agent_pvt *p = ast->pvt->pvt;
517 ast_mutex_lock(&p->lock);
519 ast->pvt->pvt = NULL;
520 p->app_sleep_cond = 1;
522 if (p->start && (ast->_state != AST_STATE_UP))
523 howlong = time(NULL) - p->start;
526 /* If they're dead, go ahead and hang up on the agent now */
527 if (!ast_strlen_zero(p->loginchan)) {
528 /* Store last disconnect time */
530 gettimeofday(&p->lastdisc, NULL);
531 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
532 if (p->lastdisc.tv_usec >= 1000000) {
533 p->lastdisc.tv_usec -= 1000000;
534 p->lastdisc.tv_sec++;
536 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
538 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
540 /* Recognize the hangup and pass it along immediately */
544 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
545 if (howlong && p->autologoff && (howlong > p->autologoff)) {
546 char agent[AST_MAX_AGENT] = "";
547 long logintime = time(NULL) - p->loginstart;
549 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
550 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
554 "Reason: Autologoff\r\n"
556 p->agent, p->loginchan, logintime, ast->uniqueid);
557 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
558 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
559 p->loginchan[0] = '\0';
561 } else if (p->dead) {
562 ast_mutex_lock(&p->chan->lock);
563 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
564 ast_mutex_unlock(&p->chan->lock);
566 ast_mutex_lock(&p->chan->lock);
567 ast_moh_start(p->chan, p->moh);
568 ast_mutex_unlock(&p->chan->lock);
572 ast_mutex_unlock(&p->lock);
573 /* Release ownership of the agent to other threads (presumably running the login app). */
574 ast_mutex_unlock(&p->app_lock);
575 } else if (p->dead) {
576 /* Go ahead and lose it */
577 ast_mutex_unlock(&p->lock);
578 /* Release ownership of the agent to other threads (presumably running the login app). */
579 ast_mutex_unlock(&p->app_lock);
581 ast_mutex_unlock(&p->lock);
582 /* Release ownership of the agent to other threads (presumably running the login app). */
583 ast_mutex_unlock(&p->app_lock);
586 ast_mutex_unlock(&p->lock);
589 ast_mutex_lock(&agentlock);
591 ast_mutex_unlock(&agentlock);
593 if (p->abouttograb) {
594 /* Let the "about to grab" thread know this isn't valid anymore, and let it
597 } else if (p->dead) {
598 ast_mutex_destroy(&p->lock);
599 ast_mutex_destroy(&p->app_lock);
603 /* Not dead -- check availability now */
604 ast_mutex_lock(&p->lock);
605 /* Store last disconnect time */
606 gettimeofday(&p->lastdisc, NULL);
607 ast_mutex_unlock(&p->lock);
609 /* Release ownership of the agent to other threads (presumably running the login app). */
610 ast_mutex_unlock(&p->app_lock);
615 static int agent_cont_sleep( void *data )
621 p = (struct agent_pvt *)data;
623 ast_mutex_lock(&p->lock);
624 res = p->app_sleep_cond;
625 if (p->lastdisc.tv_sec) {
626 gettimeofday(&tv, NULL);
627 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
628 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
631 ast_mutex_unlock(&p->lock);
634 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
639 static int agent_ack_sleep( void *data )
646 /* Wait a second and look for something */
648 p = (struct agent_pvt *)data;
651 to = ast_waitfor(p->chan, to);
660 f = ast_read(p->chan);
665 if (f->frametype == AST_FRAME_DTMF)
670 ast_mutex_lock(&p->lock);
671 if (!p->app_sleep_cond) {
672 ast_mutex_unlock(&p->lock);
675 } else if (res == '#') {
676 ast_mutex_unlock(&p->lock);
680 ast_mutex_unlock(&p->lock);
688 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
690 struct ast_channel *tmp;
691 struct ast_frame null_frame = { AST_FRAME_NULL };
694 ast_log(LOG_WARNING, "No channel? :(\n");
698 tmp = ast_channel_alloc(0);
701 tmp->nativeformats = p->chan->nativeformats;
702 tmp->writeformat = p->chan->writeformat;
703 tmp->pvt->rawwriteformat = p->chan->writeformat;
704 tmp->readformat = p->chan->readformat;
705 tmp->pvt->rawreadformat = p->chan->readformat;
706 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
707 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
708 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
710 tmp->nativeformats = AST_FORMAT_SLINEAR;
711 tmp->writeformat = AST_FORMAT_SLINEAR;
712 tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
713 tmp->readformat = AST_FORMAT_SLINEAR;
714 tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
717 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
719 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
721 ast_setstate(tmp, state);
723 tmp->pvt->send_digit = agent_digit;
724 tmp->pvt->call = agent_call;
725 tmp->pvt->hangup = agent_hangup;
726 tmp->pvt->answer = agent_answer;
727 tmp->pvt->read = agent_read;
728 tmp->pvt->write = agent_write;
729 tmp->pvt->exception = agent_read;
730 tmp->pvt->indicate = agent_indicate;
731 tmp->pvt->fixup = agent_fixup;
733 ast_mutex_lock(&usecnt_lock);
735 ast_mutex_unlock(&usecnt_lock);
736 ast_update_use_count();
738 /* Wake up and wait for other applications (by definition the login app)
739 * to release this channel). Takes ownership of the agent channel
740 * to this thread only.
741 * For signalling the other thread, ast_queue_frame is used until we
742 * can safely use signals for this purpose. The pselect() needs to be
743 * implemented in the kernel for this.
745 p->app_sleep_cond = 0;
746 if( ast_mutex_trylock(&p->app_lock) )
749 ast_queue_frame(p->chan, &null_frame);
750 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
751 ast_mutex_lock(&p->app_lock);
752 ast_mutex_lock(&p->lock);
756 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
758 tmp->pvt->pvt = NULL;
759 p->app_sleep_cond = 1;
760 ast_channel_free( tmp );
761 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
762 ast_mutex_unlock(&p->app_lock);
766 p->owning_app = pthread_self();
767 /* After the above step, there should not be any blockers. */
769 if (p->chan->blocking) {
770 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
773 ast_moh_stop(p->chan);
776 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
781 static int read_agent_config(void)
783 struct ast_config *cfg;
784 struct ast_variable *v;
785 struct agent_pvt *p, *pl, *pn;
790 cfg = ast_load(config);
792 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
795 ast_mutex_lock(&agentlock);
801 strncpy(moh, "default", sizeof(moh) - 1);
802 /* set the default recording values */
803 recordagentcalls = 0;
805 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
806 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
808 savecallsin[0] = '\0';
810 v = ast_variable_browse(cfg, "agents");
812 /* Create the interface list */
813 if (!strcasecmp(v->name, "agent")) {
814 add_agent(v->value, 0);
815 } else if (!strcasecmp(v->name, "group")) {
816 group = ast_get_group(v->value);
817 } else if (!strcasecmp(v->name, "autologoff")) {
818 autologoff = atoi(v->value);
821 } else if (!strcasecmp(v->name, "ackcall")) {
822 if (!strcasecmp(v->value, "always"))
824 else if (ast_true(v->value))
828 } else if (!strcasecmp(v->name, "wrapuptime")) {
829 wrapuptime = atoi(v->value);
832 } else if (!strcasecmp(v->name, "musiconhold")) {
833 strncpy(moh, v->value, sizeof(moh) - 1);
834 } else if (!strcasecmp(v->name, "updatecdr")) {
835 updatecdr = ast_true(v->value);
836 } else if (!strcasecmp(v->name, "recordagentcalls")) {
837 recordagentcalls = ast_true(v->value);
838 } else if (!strcasecmp(v->name, "createlink")) {
839 createlink = ast_true(v->value);
840 } else if (!strcasecmp(v->name, "recordformat")) {
841 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
842 if (!strcasecmp(v->value, "wav49"))
843 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
845 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
846 } else if (!strcasecmp(v->name, "urlprefix")) {
847 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
848 if (urlprefix[strlen(urlprefix) - 1] != '/')
849 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
850 } else if (!strcasecmp(v->name, "savecallsin")) {
851 if (v->value[0] == '/')
852 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
854 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
855 if (savecallsin[strlen(savecallsin) - 1] != '/')
856 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
857 } else if (!strcasecmp(v->name, "custom_beep")) {
858 strncpy(beep, v->value, sizeof(beep) - 1);
872 /* Destroy if appropriate */
875 ast_mutex_destroy(&p->lock);
876 ast_mutex_destroy(&p->app_lock);
879 /* Cause them to hang up */
880 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
887 ast_mutex_unlock(&agentlock);
892 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
894 struct ast_channel *chan=NULL, *parent=NULL;
897 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
899 ast_mutex_lock(&agentlock);
902 if (p == newlyavailable) {
906 ast_mutex_lock(&p->lock);
907 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
908 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
909 /* We found a pending call, time to merge */
910 chan = agent_new(newlyavailable, AST_STATE_DOWN);
913 ast_mutex_unlock(&p->lock);
916 ast_mutex_unlock(&p->lock);
920 ast_mutex_unlock(&agentlock);
921 if (parent && chan) {
922 if (newlyavailable->ackcall > 1) {
923 /* Don't do beep here */
926 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
927 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
928 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
930 res = ast_waitstream(newlyavailable->chan, "");
931 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
935 /* Note -- parent may have disappeared */
936 if (p->abouttograb) {
937 newlyavailable->acknowledged = 1;
938 ast_setstate(parent, AST_STATE_UP);
939 ast_setstate(chan, AST_STATE_UP);
940 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
941 /* Go ahead and mark the channel as a zombie so that masquerade will
942 destroy it for us, and we need not call ast_hangup */
943 ast_mutex_lock(&parent->lock);
945 ast_channel_masquerade(parent, chan);
946 ast_mutex_unlock(&parent->lock);
949 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
950 agent_cleanup(newlyavailable);
953 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
954 agent_cleanup(newlyavailable);
960 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
964 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
966 ast_mutex_lock(&agentlock);
969 if (p == newlyavailable) {
973 ast_mutex_lock(&p->lock);
974 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
975 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
976 ast_mutex_unlock(&p->lock);
979 ast_mutex_unlock(&p->lock);
983 ast_mutex_unlock(&agentlock);
985 ast_mutex_unlock(&newlyavailable->lock);
986 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
987 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
988 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
990 res = ast_waitstream(newlyavailable->chan, "");
991 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
993 ast_mutex_lock(&newlyavailable->lock);
998 static struct ast_channel *agent_request(char *type, int format, void *data)
1000 struct agent_pvt *p;
1001 struct ast_channel *chan = NULL;
1003 unsigned int groupmatch;
1008 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1009 groupmatch = (1 << groupmatch);
1010 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1011 groupmatch = (1 << groupmatch);
1017 /* Check actual logged in agents first */
1018 ast_mutex_lock(&agentlock);
1021 ast_mutex_lock(&p->lock);
1022 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1023 ast_strlen_zero(p->loginchan)) {
1026 if (!p->lastdisc.tv_sec) {
1027 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1028 if (!p->owner && p->chan) {
1030 chan = agent_new(p, AST_STATE_DOWN);
1033 ast_mutex_unlock(&p->lock);
1038 ast_mutex_unlock(&p->lock);
1044 ast_mutex_lock(&p->lock);
1045 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1046 if (p->chan || !ast_strlen_zero(p->loginchan))
1048 gettimeofday(&tv, NULL);
1050 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1052 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1053 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1054 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1055 if (!p->owner && p->chan) {
1056 /* Could still get a fixed agent */
1057 chan = agent_new(p, AST_STATE_DOWN);
1058 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1059 /* Adjustable agent */
1060 p->chan = ast_request("Local", format, p->loginchan);
1062 chan = agent_new(p, AST_STATE_DOWN);
1065 ast_mutex_unlock(&p->lock);
1070 ast_mutex_unlock(&p->lock);
1075 if (!chan && waitforagent) {
1076 /* No agent available -- but we're requesting to wait for one.
1077 Allocate a place holder */
1079 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1080 p = add_agent(data, 1);
1081 p->group = groupmatch;
1082 chan = agent_new(p, AST_STATE_DOWN);
1084 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1087 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1089 ast_mutex_unlock(&agentlock);
1093 static int powerof(unsigned int v)
1096 for (x=0;x<32;x++) {
1097 if (v & (1 << x)) return x;
1102 static int agents_show(int fd, int argc, char **argv)
1104 struct agent_pvt *p;
1105 char username[AST_MAX_BUF];
1106 char location[AST_MAX_BUF] = "";
1107 char talkingto[AST_MAX_BUF] = "";
1108 char moh[AST_MAX_BUF];
1111 return RESULT_SHOWUSAGE;
1112 ast_mutex_lock(&agentlock);
1115 ast_mutex_lock(&p->lock);
1118 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1120 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1122 if (!ast_strlen_zero(p->name))
1123 snprintf(username, sizeof(username), "(%s) ", p->name);
1127 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1128 if (p->owner && p->owner->bridge) {
1129 snprintf(talkingto, sizeof(talkingto), " talking to %s", p->owner->bridge->name);
1131 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1133 } else if (!ast_strlen_zero(p->loginchan)) {
1134 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1135 talkingto[0] = '\0';
1136 if (p->acknowledged)
1137 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1139 strncpy(location, "not logged in", sizeof(location) - 1);
1140 talkingto[0] = '\0';
1142 if (!ast_strlen_zero(p->moh))
1143 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1144 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1145 username, location, talkingto, moh);
1147 ast_mutex_unlock(&p->lock);
1150 ast_mutex_unlock(&agentlock);
1151 return RESULT_SUCCESS;
1154 static char show_agents_usage[] =
1155 "Usage: show agents\n"
1156 " Provides summary information on agents.\n";
1158 static struct ast_cli_entry cli_show_agents = {
1159 { "show", "agents", NULL }, agents_show,
1160 "Show status of agents", show_agents_usage, NULL };
1162 STANDARD_LOCAL_USER;
1165 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1169 struct agent_pvt *p;
1170 struct localuser *u;
1172 char user[AST_MAX_AGENT] = "";
1173 char pass[AST_MAX_AGENT];
1174 char agent[AST_MAX_AGENT] = "";
1175 char xpass[AST_MAX_AGENT] = "";
1178 char *opt_user = NULL;
1179 char *options = NULL;
1180 char *context = NULL;
1182 int play_announcement;
1183 char *filename = "agent-loginok";
1187 /* Parse the arguments XXX Check for failure XXX */
1188 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1191 options = strchr(opt_user, '|');
1196 context = strchr(options, '@');
1202 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1209 if (chan->_state != AST_STATE_UP)
1210 res = ast_answer(chan);
1212 if( opt_user && !ast_strlen_zero(opt_user))
1213 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1215 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1217 while (!res && (tries < 3)) {
1218 /* Check for password */
1219 ast_mutex_lock(&agentlock);
1222 if (!strcmp(p->agent, user) && !p->pending)
1223 strncpy(xpass, p->password, sizeof(xpass) - 1);
1226 ast_mutex_unlock(&agentlock);
1228 if (!ast_strlen_zero(xpass))
1229 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1233 errmsg = "agent-incorrect";
1236 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1239 /* Check again for accuracy */
1240 ast_mutex_lock(&agentlock);
1243 ast_mutex_lock(&p->lock);
1244 if (!strcmp(p->agent, user) &&
1245 !strcmp(p->password, pass) && !p->pending) {
1247 char last_loginchan[80] = "";
1249 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1252 char tmpchan[AST_MAX_BUF] = "";
1254 /* Retrieve login chan */
1257 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1260 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1261 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1265 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1269 res = ast_streamfile(chan, "invalid", chan->language);
1271 res = ast_waitstream(chan, AST_DIGIT_ANY);
1283 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1284 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1286 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1287 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1289 if (ast_strlen_zero(p->loginchan))
1290 filename = "agent-loggedoff";
1291 p->acknowledged = 0;
1292 /* store/clear the global variable that stores agentid based on the callerid */
1293 if (chan->callerid) {
1294 char agentvar[AST_MAX_BUF];
1295 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->callerid);
1296 if (ast_strlen_zero(p->loginchan))
1297 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1299 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1301 if(updatecdr && chan->cdr)
1302 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1306 p->loginchan[0] = '\0';
1307 p->acknowledged = 0;
1309 play_announcement = 1;
1311 if( strchr( options, 's' ) )
1312 play_announcement = 0;
1313 ast_mutex_unlock(&p->lock);
1314 ast_mutex_unlock(&agentlock);
1315 if( !res && play_announcement )
1316 res = ast_streamfile(chan, filename, chan->language);
1318 ast_waitstream(chan, "");
1319 ast_mutex_lock(&agentlock);
1320 ast_mutex_lock(&p->lock);
1322 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1324 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1327 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1329 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1331 /* Check once more just in case */
1334 if (callbackmode && !res) {
1335 /* Just say goodbye and be done with it */
1336 if (!ast_strlen_zero(p->loginchan)) {
1337 if (p->loginstart == 0)
1338 time(&p->loginstart);
1339 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1343 p->agent, p->loginchan, chan->uniqueid);
1344 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1345 if (option_verbose > 2)
1346 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1348 logintime = time(NULL) - p->loginstart;
1350 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1353 "Logintime: %ld\r\n"
1355 p->agent, last_loginchan, logintime, chan->uniqueid);
1356 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1357 if (option_verbose > 2)
1358 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged out\n", p->agent);
1360 ast_mutex_unlock(&agentlock);
1362 res = ast_safe_sleep(chan, 500);
1363 res = ast_streamfile(chan, "vm-goodbye", chan->language);
1365 res = ast_waitstream(chan, "");
1367 res = ast_safe_sleep(chan, 1000);
1368 ast_mutex_unlock(&p->lock);
1370 #ifdef HONOR_MUSIC_CLASS
1371 /* check if the moh class was changed with setmusiconhold */
1372 if (*(chan->musicclass))
1373 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1375 ast_moh_start(chan, p->moh);
1376 if (p->loginstart == 0)
1377 time(&p->loginstart);
1378 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1382 p->agent, chan->name, chan->uniqueid);
1383 if (updatecdr && chan->cdr)
1384 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1385 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1386 if (option_verbose > 2)
1387 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1388 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1389 /* Login this channel and wait for it to
1395 check_availability(p, 0);
1396 ast_mutex_unlock(&p->lock);
1397 ast_mutex_unlock(&agentlock);
1399 ast_mutex_lock(&p->lock);
1400 if (p->chan != chan)
1402 ast_mutex_unlock(&p->lock);
1403 /* Yield here so other interested threads can kick in. */
1408 ast_mutex_lock(&agentlock);
1409 ast_mutex_lock(&p->lock);
1410 if (p->lastdisc.tv_sec) {
1411 gettimeofday(&tv, NULL);
1412 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1413 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1414 ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1415 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1419 check_availability(p, 0);
1422 ast_mutex_unlock(&p->lock);
1423 ast_mutex_unlock(&agentlock);
1424 /* Synchronize channel ownership between call to agent and itself. */
1425 ast_mutex_lock( &p->app_lock );
1426 ast_mutex_lock(&p->lock);
1427 p->owning_app = pthread_self();
1428 ast_mutex_unlock(&p->lock);
1430 res = agent_ack_sleep(p);
1432 res = ast_safe_sleep_conditional( chan, 1000,
1433 agent_cont_sleep, p );
1434 ast_mutex_unlock( &p->app_lock );
1435 if ((p->ackcall > 1) && (res == 1)) {
1436 ast_mutex_lock(&agentlock);
1437 ast_mutex_lock(&p->lock);
1438 check_availability(p, 0);
1439 ast_mutex_unlock(&p->lock);
1440 ast_mutex_unlock(&agentlock);
1445 ast_mutex_lock(&p->lock);
1446 if (res && p->owner)
1447 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1448 /* Log us off if appropriate */
1449 if (p->chan == chan)
1451 p->acknowledged = 0;
1452 logintime = time(NULL) - p->loginstart;
1454 ast_mutex_unlock(&p->lock);
1455 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1457 "Logintime: %ld\r\n"
1459 p->agent, logintime, chan->uniqueid);
1460 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1461 if (option_verbose > 2)
1462 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1463 /* If there is no owner, go ahead and kill it now */
1464 if (p->dead && !p->owner) {
1465 ast_mutex_destroy(&p->lock);
1466 ast_mutex_destroy(&p->app_lock);
1471 ast_mutex_unlock(&p->lock);
1476 ast_mutex_unlock(&p->lock);
1477 errmsg = "agent-alreadyon";
1482 ast_mutex_unlock(&p->lock);
1486 ast_mutex_unlock(&agentlock);
1489 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1492 LOCAL_USER_REMOVE(u);
1497 static int login_exec(struct ast_channel *chan, void *data)
1499 return __login_exec(chan, data, 0);
1502 static int callback_exec(struct ast_channel *chan, void *data)
1504 return __login_exec(chan, data, 1);
1507 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1509 int exitifnoagentid = 0;
1512 char agent[AST_MAX_AGENT], *tmp;
1514 if (strchr(data, 'd'))
1515 exitifnoagentid = 1;
1516 if (strchr(data, 'n'))
1519 if (chan->callerid) {
1520 char agentvar[AST_MAX_BUF];
1521 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->callerid);
1522 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1523 struct agent_pvt *p = agents;
1524 strncpy(agent, tmp, sizeof(agent) - 1);
1525 ast_mutex_lock(&agentlock);
1527 if (!strcasecmp(p->agent, tmp)) {
1528 __agent_start_monitoring(chan, p, 1);
1533 ast_mutex_unlock(&agentlock);
1538 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);
1543 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");
1545 /* check if there is n + 101 priority */
1547 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) {
1548 chan->priority+=100;
1549 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1551 else if (exitifnoagentid)
1559 /* Make sure we can register our sip channel type */
1560 if (ast_channel_register(type, tdesc, capability, agent_request)) {
1561 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1564 ast_register_application(app, login_exec, synopsis, descrip);
1565 ast_register_application(app2, callback_exec, synopsis2, descrip2);
1566 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1567 ast_cli_register(&cli_show_agents);
1568 /* Read in the config */
1569 read_agent_config();
1575 read_agent_config();
1581 struct agent_pvt *p;
1582 /* First, take us out of the channel loop */
1583 ast_cli_unregister(&cli_show_agents);
1584 ast_unregister_application(app);
1585 ast_unregister_application(app2);
1586 ast_unregister_application(app3);
1587 ast_channel_unregister(type);
1588 if (!ast_mutex_lock(&agentlock)) {
1589 /* Hangup all interfaces if they have an owner */
1593 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1597 ast_mutex_unlock(&agentlock);
1599 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1608 ast_mutex_lock(&usecnt_lock);
1610 ast_mutex_unlock(&usecnt_lock);
1616 return ASTERISK_GPL_KEY;