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 <asterisk/causes.h>
38 #include <sys/socket.h>
44 #include <arpa/inet.h>
45 #include <sys/signal.h>
47 static char *desc = "Agent Proxy Channel";
48 static char *type = "Agent";
49 static char *tdesc = "Call Agent Proxy Channel";
50 static char *config = "agents.conf";
52 static char *app = "AgentLogin";
53 static char *app2 = "AgentCallbackLogin";
54 static char *app3 = "AgentMonitorOutgoing";
56 static char *synopsis = "Call agent login";
57 static char *synopsis2 = "Call agent callback login";
58 static char *synopsis3 = "Record agent's outgoing call";
60 static char *descrip =
61 " AgentLogin([AgentNo][|options]):\n"
62 "Asks the agent to login to the system. Always returns -1. While\n"
63 "logged in, the agent can receive calls and will hear a 'beep'\n"
64 "when a new call comes in. The agent can dump the call by pressing\n"
66 "The option string may contain zero or more of the following characters:\n"
67 " 's' -- silent login - do not announce the login ok segment after agent logged in/off\n";
69 static char *descrip2 =
70 " AgentCallbackLogin([AgentNo][|[options][exten]@context]):\n"
71 "Asks the agent to login to the system with callback.\n"
72 "The agent's callback extension is called (optionally with the specified\n"
74 "The option string may contain zero or more of the following characters:\n"
75 " 's' -- silent login - do not announce the login ok segment agent logged in/off\n";
79 static char *descrip3 =
80 " AgentMonitorOutgoing([options]):\n"
81 "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"
82 " 'd' - make the app return -1 if there is an error condition and there is no extension n+101\n"
83 " '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";
85 static char moh[80] = "default";
87 #define AST_MAX_AGENT 80 /* Agent ID or Password max length */
88 #define AST_MAX_BUF 256
89 #define AST_MAX_FILENAME_LEN 256
91 static int capability = -1;
93 static unsigned int group;
94 static int autologoff;
95 static int wrapuptime;
98 static int maxlogintries = 3;
99 static char agentgoodbye[AST_MAX_FILENAME_LEN] = "vm-goodbye";
101 static int usecnt =0;
102 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
104 /* Protect the interface list (of sip_pvt's) */
105 AST_MUTEX_DEFINE_STATIC(agentlock);
107 static int recordagentcalls = 0;
108 static char recordformat[AST_MAX_BUF] = "";
109 static char recordformatext[AST_MAX_BUF] = "";
110 static int createlink = 0;
111 static char urlprefix[AST_MAX_BUF] = "";
112 static char savecallsin[AST_MAX_BUF] = "";
113 static int updatecdr = 0;
114 static char beep[AST_MAX_BUF] = "beep";
116 #define GETAGENTBYCALLERID "AGENTBYCALLERID"
118 static struct agent_pvt {
119 ast_mutex_t lock; /* Channel private lock */
120 int dead; /* Poised for destruction? */
121 int pending; /* Not a real agent -- just pending a match */
122 int abouttograb; /* About to grab */
123 int autologoff; /* Auto timeout time */
124 int ackcall; /* ackcall */
125 time_t loginstart; /* When agent first logged in (0 when logged off) */
126 time_t start; /* When call started */
127 struct timeval lastdisc; /* When last disconnected */
128 int wrapuptime; /* Wrapup time in ms */
129 unsigned int group; /* Group memberships */
130 int acknowledged; /* Acknowledged */
131 char moh[80]; /* Which music on hold */
132 char agent[AST_MAX_AGENT]; /* Agent ID */
133 char password[AST_MAX_AGENT]; /* Password for Agent login */
134 char name[AST_MAX_AGENT];
135 ast_mutex_t app_lock; /* Synchronization between owning applications */
136 volatile pthread_t owning_app; /* Owning application thread id */
137 volatile int app_sleep_cond; /* Sleep condition for the login app */
138 struct ast_channel *owner; /* Agent */
140 struct ast_channel *chan; /* Channel we use */
141 struct agent_pvt *next; /* Agent */
144 #define CHECK_FORMATS(ast, p) do { \
146 if (ast->nativeformats != p->chan->nativeformats) { \
147 ast_log(LOG_DEBUG, "Native formats changing from %d to %d\n", ast->nativeformats, p->chan->nativeformats); \
148 /* Native formats changed, reset things */ \
149 ast->nativeformats = p->chan->nativeformats; \
150 ast_log(LOG_DEBUG, "Resetting read to %d and write to %d\n", ast->readformat, ast->writeformat);\
151 ast_set_read_format(ast, ast->readformat); \
152 ast_set_write_format(ast, ast->writeformat); \
154 if (p->chan->readformat != ast->pvt->rawreadformat) \
155 ast_set_read_format(p->chan, ast->pvt->rawreadformat); \
156 if (p->chan->writeformat != ast->pvt->rawwriteformat) \
157 ast_set_write_format(p->chan, ast->pvt->rawwriteformat); \
161 /* Cleanup moves all the relevant FD's from the 2nd to the first, but retains things
162 properly for a timingfd XXX This might need more work if agents were logged in as agents or other
163 totally impractical combinations XXX */
165 #define CLEANUP(ast, p) do { \
168 for (x=0;x<AST_MAX_FDS;x++) {\
169 if (x != AST_MAX_FDS - 2) \
170 ast->fds[x] = p->chan->fds[x]; \
172 ast->fds[AST_MAX_FDS - 3] = p->chan->fds[AST_MAX_FDS - 2]; \
177 static void agent_unlink(struct agent_pvt *agent)
179 struct agent_pvt *p, *prev;
185 prev->next = agent->next;
187 agents = agent->next;
195 static struct agent_pvt *add_agent(char *agent, int pending)
197 char tmp[AST_MAX_BUF] = "";
198 char *password=NULL, *name=NULL;
199 struct agent_pvt *p, *prev;
201 strncpy(tmp, agent, sizeof(tmp) - 1);
202 if ((password = strchr(tmp, ','))) {
205 while (*password < 33) password++;
207 if (password && (name = strchr(password, ','))) {
210 while (*name < 33) name++;
215 if (!pending && !strcmp(p->agent, tmp))
221 p = malloc(sizeof(struct agent_pvt));
223 memset(p, 0, sizeof(struct agent_pvt));
224 strncpy(p->agent, tmp, sizeof(p->agent) -1);
225 ast_mutex_init(&p->lock);
226 ast_mutex_init(&p->app_lock);
227 p->owning_app = (pthread_t) -1;
228 p->app_sleep_cond = 1;
230 p->pending = pending;
241 strncpy(p->password, password ? password : "", sizeof(p->password) - 1);
242 strncpy(p->name, name ? name : "", sizeof(p->name) - 1);
243 strncpy(p->moh, moh, sizeof(p->moh) - 1);
244 p->ackcall = ackcall;
245 p->autologoff = autologoff;
246 p->wrapuptime = wrapuptime;
254 static int agent_cleanup(struct agent_pvt *p)
256 struct ast_channel *chan = p->owner;
258 chan->pvt->pvt = NULL;
259 p->app_sleep_cond = 1;
260 /* Release ownership of the agent to other threads (presumably running the login app). */
261 ast_mutex_unlock(&p->app_lock);
263 ast_channel_free(chan);
265 ast_mutex_destroy(&p->lock);
266 ast_mutex_destroy(&p->app_lock);
272 static int check_availability(struct agent_pvt *newlyavailable, int needlock);
274 static int agent_answer(struct ast_channel *ast)
276 ast_log(LOG_WARNING, "Huh? Agent is being asked to answer?\n");
280 static int __agent_start_monitoring(struct ast_channel *ast, struct agent_pvt *p, int needlock)
282 char tmp[AST_MAX_BUF],tmp2[AST_MAX_BUF], *pointer;
283 char filename[AST_MAX_BUF];
288 snprintf(filename, sizeof(filename), "agent-%s-%s",p->agent, ast->uniqueid);
289 /* substitute . for - */
290 if ((pointer = strchr(filename, '.')))
292 snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
293 ast_monitor_start(ast, recordformat, tmp, needlock);
294 ast_monitor_setjoinfiles(ast, 1);
295 snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
297 ast_verbose("name is %s, link is %s\n",tmp, tmp2);
300 ast->cdr = ast_cdr_alloc();
301 ast_cdr_setuserfield(ast, tmp2);
304 ast_log(LOG_ERROR, "Recording already started on that call.\n");
308 static int agent_start_monitoring(struct ast_channel *ast, int needlock)
310 return __agent_start_monitoring(ast, ast->pvt->pvt, needlock);
313 static struct ast_frame *agent_read(struct ast_channel *ast)
315 struct agent_pvt *p = ast->pvt->pvt;
316 struct ast_frame *f = NULL;
317 static struct ast_frame null_frame = { AST_FRAME_NULL, };
318 static struct ast_frame answer_frame = { AST_FRAME_CONTROL, AST_CONTROL_ANSWER };
319 ast_mutex_lock(&p->lock);
320 CHECK_FORMATS(ast, p);
322 p->chan->exception = ast->exception;
323 if (ast->fdno == AST_MAX_FDS - 3)
324 p->chan->fdno = AST_MAX_FDS - 2;
326 p->chan->fdno = ast->fdno;
327 f = ast_read(p->chan);
331 /* If there's a channel, hang it up (if it's on a callback) make it NULL */
333 /* Note that we don't hangup if it's not a callback because Asterisk will do it
334 for us when the PBX instance that called login finishes */
335 if (!ast_strlen_zero(p->loginchan)) {
336 p->chan->_bridge = NULL;
339 gettimeofday(&p->lastdisc, NULL);
340 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
341 if (p->lastdisc.tv_usec > 1000000) {
342 p->lastdisc.tv_usec -= 1000000;
343 p->lastdisc.tv_sec++;
345 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
352 if (f && (f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
355 if (option_verbose > 2)
356 ast_verbose(VERBOSE_PREFIX_3 "%s answered, waiting for '#' to acknowledge\n", p->chan->name);
357 /* Don't pass answer along */
365 p->chan->_bridge = ast;
369 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
370 if (!p->acknowledged) {
371 if (option_verbose > 2)
372 ast_verbose(VERBOSE_PREFIX_3 "%s acknowledged\n", p->chan->name);
377 p->chan->_bridge = ast;
380 if (f && (f->frametype == AST_FRAME_DTMF) && (f->subclass == '*')) {
381 /* * terminates call */
386 ast_mutex_unlock(&p->lock);
387 if (recordagentcalls && f == &answer_frame)
388 agent_start_monitoring(ast,0);
392 static int agent_write(struct ast_channel *ast, struct ast_frame *f)
394 struct agent_pvt *p = ast->pvt->pvt;
396 CHECK_FORMATS(ast, p);
397 ast_mutex_lock(&p->lock);
399 if ((f->frametype != AST_FRAME_VOICE) ||
400 (f->subclass == p->chan->writeformat)) {
401 res = ast_write(p->chan, f);
403 ast_log(LOG_DEBUG, "Dropping one incompatible voice frame on '%s' to '%s'\n", ast->name, p->chan->name);
409 ast_mutex_unlock(&p->lock);
413 static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
415 struct agent_pvt *p = newchan->pvt->pvt;
416 ast_mutex_lock(&p->lock);
417 if (p->owner != oldchan) {
418 ast_log(LOG_WARNING, "old channel wasn't %p but was %p\n", oldchan, p->owner);
419 ast_mutex_unlock(&p->lock);
423 ast_mutex_unlock(&p->lock);
427 static int agent_indicate(struct ast_channel *ast, int condition)
429 struct agent_pvt *p = ast->pvt->pvt;
431 ast_mutex_lock(&p->lock);
433 res = ast_indicate(p->chan, condition);
436 ast_mutex_unlock(&p->lock);
440 static int agent_digit(struct ast_channel *ast, char digit)
442 struct agent_pvt *p = ast->pvt->pvt;
444 ast_mutex_lock(&p->lock);
446 res = p->chan->pvt->send_digit(p->chan, digit);
449 ast_mutex_unlock(&p->lock);
453 static int agent_call(struct ast_channel *ast, char *dest, int timeout)
455 struct agent_pvt *p = ast->pvt->pvt;
457 ast_mutex_lock(&p->lock);
461 ast_log(LOG_DEBUG, "Pretending to dial on pending agent\n");
462 ast_setstate(ast, AST_STATE_DIALING);
465 ast_log(LOG_NOTICE, "Whoa, they hung up between alloc and call... what are the odds of that?\n");
468 ast_mutex_unlock(&p->lock);
470 } else if (!ast_strlen_zero(p->loginchan)) {
472 /* Call on this agent */
473 if (option_verbose > 2)
474 ast_verbose(VERBOSE_PREFIX_3 "outgoing agentcall, to agent '%s', on '%s'\n", p->agent, p->chan->name);
475 if (p->chan->cid.cid_num)
476 free(p->chan->cid.cid_num);
477 if (ast->cid.cid_num)
478 p->chan->cid.cid_num = strdup(ast->cid.cid_num);
480 p->chan->cid.cid_num = NULL;
481 if (p->chan->cid.cid_name)
482 free(p->chan->cid.cid_name);
483 if (ast->cid.cid_name)
484 p->chan->cid.cid_name = strdup(ast->cid.cid_name);
486 p->chan->cid.cid_name = NULL;
487 res = ast_call(p->chan, p->loginchan, 0);
489 ast_mutex_unlock(&p->lock);
492 ast_verbose( VERBOSE_PREFIX_3 "agent_call, call to agent '%s' call on '%s'\n", p->agent, p->chan->name);
493 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", p->chan->language);
494 res = ast_streamfile(p->chan, beep, p->chan->language);
495 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
497 res = ast_waitstream(p->chan, "");
498 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
501 res = ast_set_read_format(p->chan, ast_best_codec(p->chan->nativeformats));
502 ast_log( LOG_DEBUG, "Set read format, result '%d'\n", res);
504 ast_log(LOG_WARNING, "Unable to set read format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
511 ast_set_write_format(p->chan, ast_best_codec(p->chan->nativeformats));
512 ast_log( LOG_DEBUG, "Set write format, result '%d'\n", res);
514 ast_log(LOG_WARNING, "Unable to set write format to %s\n", ast_getformatname(ast_best_codec(p->chan->nativeformats)));
518 /* Call is immediately up, or might need ack */
520 ast_setstate(ast, AST_STATE_RINGING);
522 ast_setstate(ast, AST_STATE_UP);
523 if (recordagentcalls)
524 agent_start_monitoring(ast,0);
530 ast_mutex_unlock(&p->lock);
534 static int agent_hangup(struct ast_channel *ast)
536 struct agent_pvt *p = ast->pvt->pvt;
538 ast_mutex_lock(&p->lock);
540 ast->pvt->pvt = NULL;
541 p->app_sleep_cond = 1;
544 /* if they really are hung up then set start to 0 so the test
545 * later if we're called on an already downed channel
546 * doesn't cause an agent to be logged out like when
547 * agent_request() is followed immediately by agent_hangup()
548 * as in apps/app_chanisavail.c:chanavail_exec()
551 ast_log(LOG_DEBUG, "Hangup called for state %s\n", ast_state2str(ast->_state));
552 if (p->start && (ast->_state != AST_STATE_UP)) {
553 howlong = time(NULL) - p->start;
555 } else if (ast->_state == AST_STATE_RESERVED) {
560 /* If they're dead, go ahead and hang up on the agent now */
561 if (!ast_strlen_zero(p->loginchan)) {
562 /* Store last disconnect time */
564 gettimeofday(&p->lastdisc, NULL);
565 p->lastdisc.tv_usec += (p->wrapuptime % 1000) * 1000;
566 if (p->lastdisc.tv_usec >= 1000000) {
567 p->lastdisc.tv_usec -= 1000000;
568 p->lastdisc.tv_sec++;
570 p->lastdisc.tv_sec += (p->wrapuptime / 1000);
572 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
574 /* Recognize the hangup and pass it along immediately */
578 ast_log(LOG_DEBUG, "Hungup, howlong is %d, autologoff is %d\n", howlong, p->autologoff);
579 if (howlong && p->autologoff && (howlong > p->autologoff)) {
580 char agent[AST_MAX_AGENT] = "";
581 long logintime = time(NULL) - p->loginstart;
583 ast_log(LOG_NOTICE, "Agent '%s' didn't answer/confirm within %d seconds (waited %d)\n", p->name, p->autologoff, howlong);
584 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
588 "Reason: Autologoff\r\n"
590 p->agent, p->loginchan, logintime, ast->uniqueid);
591 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
592 ast_queue_log("NONE", ast->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|%s", p->loginchan, logintime, "Autologoff");
593 p->loginchan[0] = '\0';
594 ast_device_state_changed("Agent/%s", p->agent);
596 } else if (p->dead) {
597 ast_mutex_lock(&p->chan->lock);
598 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
599 ast_mutex_unlock(&p->chan->lock);
601 ast_mutex_lock(&p->chan->lock);
602 ast_moh_start(p->chan, p->moh);
603 ast_mutex_unlock(&p->chan->lock);
607 ast_mutex_unlock(&p->lock);
608 /* Release ownership of the agent to other threads (presumably running the login app). */
609 ast_mutex_unlock(&p->app_lock);
610 } else if (p->dead) {
611 /* Go ahead and lose it */
612 ast_mutex_unlock(&p->lock);
613 /* Release ownership of the agent to other threads (presumably running the login app). */
614 ast_mutex_unlock(&p->app_lock);
616 ast_mutex_unlock(&p->lock);
617 /* Release ownership of the agent to other threads (presumably running the login app). */
618 ast_mutex_unlock(&p->app_lock);
621 ast_mutex_unlock(&p->lock);
624 ast_mutex_lock(&agentlock);
626 ast_mutex_unlock(&agentlock);
628 if (p->abouttograb) {
629 /* Let the "about to grab" thread know this isn't valid anymore, and let it
632 } else if (p->dead) {
633 ast_mutex_destroy(&p->lock);
634 ast_mutex_destroy(&p->app_lock);
638 /* Not dead -- check availability now */
639 ast_mutex_lock(&p->lock);
640 /* Store last disconnect time */
641 gettimeofday(&p->lastdisc, NULL);
642 ast_mutex_unlock(&p->lock);
644 /* Release ownership of the agent to other threads (presumably running the login app). */
645 ast_mutex_unlock(&p->app_lock);
650 static int agent_cont_sleep( void *data )
656 p = (struct agent_pvt *)data;
658 ast_mutex_lock(&p->lock);
659 res = p->app_sleep_cond;
660 if (p->lastdisc.tv_sec) {
661 gettimeofday(&tv, NULL);
662 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
663 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime)
666 ast_mutex_unlock(&p->lock);
669 ast_log( LOG_DEBUG, "agent_cont_sleep() returning %d\n", res );
674 static int agent_ack_sleep( void *data )
681 /* Wait a second and look for something */
683 p = (struct agent_pvt *)data;
686 to = ast_waitfor(p->chan, to);
695 f = ast_read(p->chan);
700 if (f->frametype == AST_FRAME_DTMF)
705 ast_mutex_lock(&p->lock);
706 if (!p->app_sleep_cond) {
707 ast_mutex_unlock(&p->lock);
710 } else if (res == '#') {
711 ast_mutex_unlock(&p->lock);
715 ast_mutex_unlock(&p->lock);
723 static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge)
726 struct ast_channel *ret=NULL;
728 p = bridge->pvt->pvt;
730 ret = bridge->_bridge;
731 else if (chan == bridge->_bridge)
736 static struct ast_channel *agent_new(struct agent_pvt *p, int state)
738 struct ast_channel *tmp;
739 struct ast_frame null_frame = { AST_FRAME_NULL };
742 ast_log(LOG_WARNING, "No channel? :(\n");
746 tmp = ast_channel_alloc(0);
749 tmp->nativeformats = p->chan->nativeformats;
750 tmp->writeformat = p->chan->writeformat;
751 tmp->pvt->rawwriteformat = p->chan->writeformat;
752 tmp->readformat = p->chan->readformat;
753 tmp->pvt->rawreadformat = p->chan->readformat;
754 strncpy(tmp->language, p->chan->language, sizeof(tmp->language)-1);
755 strncpy(tmp->context, p->chan->context, sizeof(tmp->context)-1);
756 strncpy(tmp->exten, p->chan->exten, sizeof(tmp->exten)-1);
758 tmp->nativeformats = AST_FORMAT_SLINEAR;
759 tmp->writeformat = AST_FORMAT_SLINEAR;
760 tmp->pvt->rawwriteformat = AST_FORMAT_SLINEAR;
761 tmp->readformat = AST_FORMAT_SLINEAR;
762 tmp->pvt->rawreadformat = AST_FORMAT_SLINEAR;
765 snprintf(tmp->name, sizeof(tmp->name), "Agent/P%s-%d", p->agent, rand() & 0xffff);
767 snprintf(tmp->name, sizeof(tmp->name), "Agent/%s", p->agent);
769 ast_setstate(tmp, state);
771 tmp->pvt->send_digit = agent_digit;
772 tmp->pvt->call = agent_call;
773 tmp->pvt->hangup = agent_hangup;
774 tmp->pvt->answer = agent_answer;
775 tmp->pvt->read = agent_read;
776 tmp->pvt->write = agent_write;
777 tmp->pvt->exception = agent_read;
778 tmp->pvt->indicate = agent_indicate;
779 tmp->pvt->fixup = agent_fixup;
780 tmp->pvt->bridged_channel = agent_bridgedchannel;
782 ast_mutex_lock(&usecnt_lock);
784 ast_mutex_unlock(&usecnt_lock);
785 ast_update_use_count();
787 /* Wake up and wait for other applications (by definition the login app)
788 * to release this channel). Takes ownership of the agent channel
789 * to this thread only.
790 * For signalling the other thread, ast_queue_frame is used until we
791 * can safely use signals for this purpose. The pselect() needs to be
792 * implemented in the kernel for this.
794 p->app_sleep_cond = 0;
795 if( ast_mutex_trylock(&p->app_lock) )
798 ast_queue_frame(p->chan, &null_frame);
799 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
800 ast_mutex_lock(&p->app_lock);
801 ast_mutex_lock(&p->lock);
805 ast_log(LOG_WARNING, "Agent disconnected while we were connecting the call\n");
807 tmp->pvt->pvt = NULL;
808 p->app_sleep_cond = 1;
809 ast_channel_free( tmp );
810 ast_mutex_unlock(&p->lock); /* For other thread to read the condition. */
811 ast_mutex_unlock(&p->app_lock);
815 p->owning_app = pthread_self();
816 /* After the above step, there should not be any blockers. */
818 if (p->chan->blocking) {
819 ast_log( LOG_ERROR, "A blocker exists after agent channel ownership acquired\n" );
822 ast_moh_stop(p->chan);
825 ast_log(LOG_WARNING, "Unable to allocate channel structure\n");
830 static int read_agent_config(void)
832 struct ast_config *cfg;
833 struct ast_variable *v;
834 struct agent_pvt *p, *pl, *pn;
839 cfg = ast_load(config);
841 ast_log(LOG_NOTICE, "No agent configuration found -- agent support disabled\n");
844 ast_mutex_lock(&agentlock);
850 strncpy(moh, "default", sizeof(moh) - 1);
851 /* set the default recording values */
852 recordagentcalls = 0;
854 strncpy(recordformat, "wav", sizeof(recordformat) - 1);
855 strncpy(recordformatext, "wav", sizeof(recordformatext) - 1);
857 savecallsin[0] = '\0';
859 v = ast_variable_browse(cfg, "agents");
861 /* Create the interface list */
862 if (!strcasecmp(v->name, "agent")) {
863 add_agent(v->value, 0);
864 } else if (!strcasecmp(v->name, "group")) {
865 group = ast_get_group(v->value);
866 } else if (!strcasecmp(v->name, "autologoff")) {
867 autologoff = atoi(v->value);
870 } else if (!strcasecmp(v->name, "ackcall")) {
871 if (!strcasecmp(v->value, "always"))
873 else if (ast_true(v->value))
877 } else if (!strcasecmp(v->name, "wrapuptime")) {
878 wrapuptime = atoi(v->value);
881 } else if (!strcasecmp(v->name, "maxlogintries") && !ast_strlen_zero(v->value)) {
882 maxlogintries = atoi(v->value);
883 if (maxlogintries < 0)
885 } else if (!strcasecmp(v->name, "goodbye") && !ast_strlen_zero(v->value)) {
886 strcpy(agentgoodbye,v->value);
887 } else if (!strcasecmp(v->name, "musiconhold")) {
888 strncpy(moh, v->value, sizeof(moh) - 1);
889 } else if (!strcasecmp(v->name, "updatecdr")) {
890 if (ast_true(v->value))
894 } else if (!strcasecmp(v->name, "recordagentcalls")) {
895 recordagentcalls = ast_true(v->value);
896 } else if (!strcasecmp(v->name, "createlink")) {
897 createlink = ast_true(v->value);
898 } else if (!strcasecmp(v->name, "recordformat")) {
899 strncpy(recordformat, v->value, sizeof(recordformat) - 1);
900 if (!strcasecmp(v->value, "wav49"))
901 strncpy(recordformatext, "WAV", sizeof(recordformatext) - 1);
903 strncpy(recordformatext, v->value, sizeof(recordformatext) - 1);
904 } else if (!strcasecmp(v->name, "urlprefix")) {
905 strncpy(urlprefix, v->value, sizeof(urlprefix) - 2);
906 if (urlprefix[strlen(urlprefix) - 1] != '/')
907 strncat(urlprefix, "/", sizeof(urlprefix) - strlen(urlprefix) - 1);
908 } else if (!strcasecmp(v->name, "savecallsin")) {
909 if (v->value[0] == '/')
910 strncpy(savecallsin, v->value, sizeof(savecallsin) - 2);
912 snprintf(savecallsin, sizeof(savecallsin) - 2, "/%s", v->value);
913 if (savecallsin[strlen(savecallsin) - 1] != '/')
914 strncat(savecallsin, "/", sizeof(savecallsin) - strlen(savecallsin) - 1);
915 } else if (!strcasecmp(v->name, "custom_beep")) {
916 strncpy(beep, v->value, sizeof(beep) - 1);
930 /* Destroy if appropriate */
933 ast_mutex_destroy(&p->lock);
934 ast_mutex_destroy(&p->app_lock);
937 /* Cause them to hang up */
938 ast_softhangup(p->chan, AST_SOFTHANGUP_EXPLICIT);
945 ast_mutex_unlock(&agentlock);
950 static int check_availability(struct agent_pvt *newlyavailable, int needlock)
952 struct ast_channel *chan=NULL, *parent=NULL;
955 ast_log(LOG_DEBUG, "Checking availability of '%s'\n", newlyavailable->agent);
957 ast_mutex_lock(&agentlock);
960 if (p == newlyavailable) {
964 ast_mutex_lock(&p->lock);
965 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
966 ast_log(LOG_DEBUG, "Call '%s' looks like a winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
967 /* We found a pending call, time to merge */
968 chan = agent_new(newlyavailable, AST_STATE_DOWN);
971 ast_mutex_unlock(&p->lock);
974 ast_mutex_unlock(&p->lock);
978 ast_mutex_unlock(&agentlock);
979 if (parent && chan) {
980 if (newlyavailable->ackcall > 1) {
981 /* Don't do beep here */
984 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
985 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
986 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
988 res = ast_waitstream(newlyavailable->chan, "");
989 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
993 /* Note -- parent may have disappeared */
994 if (p->abouttograb) {
995 newlyavailable->acknowledged = 1;
996 ast_setstate(parent, AST_STATE_UP);
997 ast_setstate(chan, AST_STATE_UP);
998 strncpy(parent->context, chan->context, sizeof(parent->context) - 1);
999 /* Go ahead and mark the channel as a zombie so that masquerade will
1000 destroy it for us, and we need not call ast_hangup */
1001 ast_mutex_lock(&parent->lock);
1003 ast_channel_masquerade(parent, chan);
1004 ast_mutex_unlock(&parent->lock);
1007 ast_log(LOG_DEBUG, "Sneaky, parent disappeared in the mean time...\n");
1008 agent_cleanup(newlyavailable);
1011 ast_log(LOG_DEBUG, "Ugh... Agent hung up at exactly the wrong time\n");
1012 agent_cleanup(newlyavailable);
1018 static int check_beep(struct agent_pvt *newlyavailable, int needlock)
1020 struct agent_pvt *p;
1022 ast_log(LOG_DEBUG, "Checking beep availability of '%s'\n", newlyavailable->agent);
1024 ast_mutex_lock(&agentlock);
1027 if (p == newlyavailable) {
1031 ast_mutex_lock(&p->lock);
1032 if (!p->abouttograb && p->pending && ((p->group && (newlyavailable->group & p->group)) || !strcmp(p->agent, newlyavailable->agent))) {
1033 ast_log(LOG_DEBUG, "Call '%s' looks like a would-be winner for agent '%s'\n", p->owner->name, newlyavailable->agent);
1034 ast_mutex_unlock(&p->lock);
1037 ast_mutex_unlock(&p->lock);
1041 ast_mutex_unlock(&agentlock);
1043 ast_mutex_unlock(&newlyavailable->lock);
1044 ast_log( LOG_DEBUG, "Playing beep, lang '%s'\n", newlyavailable->chan->language);
1045 res = ast_streamfile(newlyavailable->chan, beep, newlyavailable->chan->language);
1046 ast_log( LOG_DEBUG, "Played beep, result '%d'\n", res);
1048 res = ast_waitstream(newlyavailable->chan, "");
1049 ast_log( LOG_DEBUG, "Waited for stream, result '%d'\n", res);
1051 ast_mutex_lock(&newlyavailable->lock);
1056 static struct ast_channel *agent_request(const char *type, int format, void *data, int *cause)
1058 struct agent_pvt *p;
1059 struct ast_channel *chan = NULL;
1061 unsigned int groupmatch;
1066 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1067 groupmatch = (1 << groupmatch);
1068 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1069 groupmatch = (1 << groupmatch);
1075 /* Check actual logged in agents first */
1076 ast_mutex_lock(&agentlock);
1079 ast_mutex_lock(&p->lock);
1080 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent)) &&
1081 ast_strlen_zero(p->loginchan)) {
1084 if (!p->lastdisc.tv_sec) {
1085 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1086 if (!p->owner && p->chan) {
1088 chan = agent_new(p, AST_STATE_DOWN);
1091 ast_mutex_unlock(&p->lock);
1096 ast_mutex_unlock(&p->lock);
1102 ast_mutex_lock(&p->lock);
1103 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1104 if (p->chan || !ast_strlen_zero(p->loginchan))
1106 gettimeofday(&tv, NULL);
1108 ast_log(LOG_NOTICE, "Time now: %ld, Time of lastdisc: %ld\n", tv.tv_sec, p->lastdisc.tv_sec);
1110 if (!p->lastdisc.tv_sec || (tv.tv_sec > p->lastdisc.tv_sec)) {
1111 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1112 /* Agent must be registered, but not have any active call, and not be in a waiting state */
1113 if (!p->owner && p->chan) {
1114 /* Could still get a fixed agent */
1115 chan = agent_new(p, AST_STATE_DOWN);
1116 } else if (!p->owner && !ast_strlen_zero(p->loginchan)) {
1117 /* Adjustable agent */
1118 p->chan = ast_request("Local", format, p->loginchan, cause);
1120 chan = agent_new(p, AST_STATE_DOWN);
1123 ast_mutex_unlock(&p->lock);
1128 ast_mutex_unlock(&p->lock);
1133 if (!chan && waitforagent) {
1134 /* No agent available -- but we're requesting to wait for one.
1135 Allocate a place holder */
1137 ast_log(LOG_DEBUG, "Creating place holder for '%s'\n", s);
1138 p = add_agent(data, 1);
1139 p->group = groupmatch;
1140 chan = agent_new(p, AST_STATE_DOWN);
1142 ast_log(LOG_WARNING, "Weird... Fix this to drop the unused pending agent\n");
1145 ast_log(LOG_DEBUG, "Not creating place holder for '%s' since nobody logged in\n", s);
1148 *cause = AST_CAUSE_BUSY;
1150 *cause = AST_CAUSE_UNREGISTERED;
1151 ast_mutex_unlock(&agentlock);
1155 static int powerof(unsigned int v)
1158 for (x=0;x<32;x++) {
1159 if (v & (1 << x)) return x;
1164 static int agents_show(int fd, int argc, char **argv)
1166 struct agent_pvt *p;
1167 char username[AST_MAX_BUF];
1168 char location[AST_MAX_BUF] = "";
1169 char talkingto[AST_MAX_BUF] = "";
1170 char moh[AST_MAX_BUF];
1173 return RESULT_SHOWUSAGE;
1174 ast_mutex_lock(&agentlock);
1177 ast_mutex_lock(&p->lock);
1180 ast_cli(fd, "-- Pending call to group %d\n", powerof(p->group));
1182 ast_cli(fd, "-- Pending call to agent %s\n", p->agent);
1184 if (!ast_strlen_zero(p->name))
1185 snprintf(username, sizeof(username), "(%s) ", p->name);
1189 snprintf(location, sizeof(location), "logged in on %s", p->chan->name);
1190 if (p->owner && ast_bridged_channel(p->owner)) {
1191 snprintf(talkingto, sizeof(talkingto), " talking to %s", ast_bridged_channel(p->owner)->name);
1193 strncpy(talkingto, " is idle", sizeof(talkingto) - 1);
1195 } else if (!ast_strlen_zero(p->loginchan)) {
1196 snprintf(location, sizeof(location) - 20, "available at '%s'", p->loginchan);
1197 talkingto[0] = '\0';
1198 if (p->acknowledged)
1199 strncat(location, " (Confirmed)", sizeof(location) - strlen(location) - 1);
1201 strncpy(location, "not logged in", sizeof(location) - 1);
1202 talkingto[0] = '\0';
1204 if (!ast_strlen_zero(p->moh))
1205 snprintf(moh, sizeof(moh), " (musiconhold is '%s')", p->moh);
1206 ast_cli(fd, "%-12.12s %s%s%s%s\n", p->agent,
1207 username, location, talkingto, moh);
1209 ast_mutex_unlock(&p->lock);
1212 ast_mutex_unlock(&agentlock);
1213 return RESULT_SUCCESS;
1216 static char show_agents_usage[] =
1217 "Usage: show agents\n"
1218 " Provides summary information on agents.\n";
1220 static struct ast_cli_entry cli_show_agents = {
1221 { "show", "agents", NULL }, agents_show,
1222 "Show status of agents", show_agents_usage, NULL };
1224 STANDARD_LOCAL_USER;
1227 static int __login_exec(struct ast_channel *chan, void *data, int callbackmode)
1231 int max_login_tries = maxlogintries;
1232 struct agent_pvt *p;
1233 struct localuser *u;
1235 int login_state = 0;
1236 char user[AST_MAX_AGENT] = "";
1237 char pass[AST_MAX_AGENT];
1238 char agent[AST_MAX_AGENT] = "";
1239 char xpass[AST_MAX_AGENT] = "";
1242 char *opt_user = NULL;
1243 char *options = NULL;
1246 char *tmpoptions = NULL;
1247 char *context = NULL;
1249 int play_announcement = 1;
1250 char agent_goodbye[AST_MAX_FILENAME_LEN];
1251 int update_cdr = updatecdr;
1252 char *filename = "agent-loginok";
1254 strcpy(agent_goodbye, agentgoodbye);
1257 /* Parse the arguments XXX Check for failure XXX */
1258 strncpy(info, (char *)data, strlen((char *)data) + AST_MAX_EXTENSION-1);
1260 /* Set Channel Specific Login Overrides */
1261 if (pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES") && strlen(pbx_builtin_getvar_helper(chan, "AGENTLMAXLOGINTRIES"))) {
1262 max_login_tries = atoi(pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES"));
1263 if (max_login_tries < 0)
1264 max_login_tries = 0;
1265 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTMAXLOGINTRIES");
1266 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);
1268 if (pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR") && strlen(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR"))) {
1269 if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR")))
1273 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTUPDATECDR");
1274 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTUPDATECDR=%s, setting update_cdr to: %d on Channel '%s'.\n",tmpoptions,update_cdr,chan->name);
1276 if (pbx_builtin_getvar_helper(chan, "AGENTGOODBYE") && strlen(pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"))) {
1277 strcpy(agent_goodbye, pbx_builtin_getvar_helper(chan, "AGENTGOODBYE"));
1278 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTGOODBYE");
1279 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTGOODBYE=%s, setting agent_goodbye to: %s on Channel '%s'.\n",tmpoptions,agent_goodbye,chan->name);
1281 /* End Channel Specific Login Overrides */
1282 /* Read command line options */
1284 options = strchr(opt_user, '|');
1289 context = strchr(options, '@');
1295 while(*exten && ((*exten < '0') || (*exten > '9'))) exten++;
1302 option = (char)options[0];
1304 play_announcement = 0;
1306 badoption[0] = option;
1307 badoption[1] = '\0';
1308 tmpoptions=badoption;
1309 ast_verbose(VERBOSE_PREFIX_3 "Warning: option %s is unknown.\n",tmpoptions);
1315 /* End command line options */
1317 if (chan->_state != AST_STATE_UP)
1318 res = ast_answer(chan);
1320 if( opt_user && !ast_strlen_zero(opt_user))
1321 strncpy( user, opt_user, AST_MAX_AGENT - 1);
1323 res = ast_app_getdata(chan, "agent-user", user, sizeof(user) - 1, 0);
1325 while (!res && (max_login_tries==0 || tries < max_login_tries)) {
1327 /* Check for password */
1328 ast_mutex_lock(&agentlock);
1331 if (!strcmp(p->agent, user) && !p->pending)
1332 strncpy(xpass, p->password, sizeof(xpass) - 1);
1335 ast_mutex_unlock(&agentlock);
1337 if (!ast_strlen_zero(xpass))
1338 res = ast_app_getdata(chan, "agent-pass", pass, sizeof(pass) - 1, 0);
1342 errmsg = "agent-incorrect";
1345 ast_log(LOG_NOTICE, "user: %s, pass: %s\n", user, pass);
1348 /* Check again for accuracy */
1349 ast_mutex_lock(&agentlock);
1352 ast_mutex_lock(&p->lock);
1353 if (!strcmp(p->agent, user) &&
1354 !strcmp(p->password, pass) && !p->pending) {
1355 login_state = 1; /* Successful Login */
1356 /* Set Channel Specific Agent Overides */
1357 if (pbx_builtin_getvar_helper(chan, "AGENTACKCALL") && strlen(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"))) {
1358 if (!strcasecmp(pbx_builtin_getvar_helper(chan, "AGENTACKCALL"), "always"))
1360 else if (ast_true(pbx_builtin_getvar_helper(chan, "AGENTACKCALL")))
1364 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTACKCALL");
1365 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTACKCALL=%s, setting ackcall to: %d for Agent '%s'.\n",tmpoptions,p->ackcall,p->agent);
1367 if (pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF") && strlen(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"))) {
1368 p->autologoff = atoi(pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF"));
1369 if (p->autologoff < 0)
1371 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTAUTOLOGOFF");
1372 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTAUTOLOGOFF=%s, setting autologff to: %d for Agent '%s'.\n",tmpoptions,p->autologoff,p->agent);
1374 if (pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME") && strlen(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"))) {
1375 p->wrapuptime = atoi(pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME"));
1376 if (p->wrapuptime < 0)
1378 tmpoptions=pbx_builtin_getvar_helper(chan, "AGENTWRAPUPTIME");
1379 ast_verbose(VERBOSE_PREFIX_3 "Saw variable AGENTWRAPUPTIME=%s, setting wrapuptime to: %d for Agent '%s'.\n",tmpoptions,p->wrapuptime,p->agent);
1381 /* End Channel Specific Agent Overides */
1383 char last_loginchan[80] = "";
1385 snprintf(agent, sizeof(agent), "Agent/%s", p->agent);
1388 char tmpchan[AST_MAX_BUF] = "";
1390 /* Retrieve login chan */
1393 strncpy(tmpchan, exten, sizeof(tmpchan) - 1);
1396 res = ast_app_getdata(chan, "agent-newlocation", tmpchan+pos, sizeof(tmpchan) - 2, 0);
1397 if (ast_strlen_zero(tmpchan) || ast_exists_extension(chan, context && !ast_strlen_zero(context) ? context : "default", tmpchan,
1401 ast_log(LOG_WARNING, "Extension '%s' is not valid for automatic login of agent '%s'\n", exten, p->agent);
1405 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);
1406 res = ast_streamfile(chan, "invalid", chan->language);
1408 res = ast_waitstream(chan, AST_DIGIT_ANY);
1421 if (context && !ast_strlen_zero(context) && !ast_strlen_zero(tmpchan))
1422 snprintf(p->loginchan, sizeof(p->loginchan), "%s@%s", tmpchan, context);
1424 strncpy(last_loginchan, p->loginchan, sizeof(last_loginchan) - 1);
1425 strncpy(p->loginchan, tmpchan, sizeof(p->loginchan) - 1);
1427 if (ast_strlen_zero(p->loginchan)) {
1429 filename = "agent-loggedoff";
1431 p->acknowledged = 0;
1432 /* store/clear the global variable that stores agentid based on the callerid */
1433 if (chan->cid.cid_num) {
1434 char agentvar[AST_MAX_BUF];
1435 snprintf(agentvar, sizeof(agentvar), "%s_%s",GETAGENTBYCALLERID, chan->cid.cid_num);
1436 if (ast_strlen_zero(p->loginchan))
1437 pbx_builtin_setvar_helper(NULL, agentvar, NULL);
1439 pbx_builtin_setvar_helper(NULL, agentvar, p->agent);
1441 if(update_cdr && chan->cdr)
1442 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1446 p->loginchan[0] = '\0';
1447 p->acknowledged = 0;
1449 ast_mutex_unlock(&p->lock);
1450 ast_mutex_unlock(&agentlock);
1451 if( !res && play_announcement==1 )
1452 res = ast_streamfile(chan, filename, chan->language);
1454 ast_waitstream(chan, "");
1455 ast_mutex_lock(&agentlock);
1456 ast_mutex_lock(&p->lock);
1458 res = ast_set_read_format(chan, ast_best_codec(chan->nativeformats));
1460 ast_log(LOG_WARNING, "Unable to set read format to %d\n", ast_best_codec(chan->nativeformats));
1463 ast_set_write_format(chan, ast_best_codec(chan->nativeformats));
1465 ast_log(LOG_WARNING, "Unable to set write format to %d\n", ast_best_codec(chan->nativeformats));
1467 /* Check once more just in case */
1470 if (callbackmode && !res) {
1471 /* Just say goodbye and be done with it */
1472 if (!ast_strlen_zero(p->loginchan)) {
1473 if (p->loginstart == 0)
1474 time(&p->loginstart);
1475 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogin",
1479 p->agent, p->loginchan, chan->uniqueid);
1480 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGIN", "%s", p->loginchan);
1481 if (option_verbose > 2)
1482 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged in on %s\n", p->agent, p->loginchan);
1483 ast_device_state_changed("Agent/%s", p->agent);
1485 logintime = time(NULL) - p->loginstart;
1487 manager_event(EVENT_FLAG_AGENT, "Agentcallbacklogoff",
1490 "Logintime: %ld\r\n"
1492 p->agent, last_loginchan, logintime, chan->uniqueid);
1493 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTCALLBACKLOGOFF", "%s|%ld|", last_loginchan, logintime);
1494 if (option_verbose > 2)
1495 ast_verbose(VERBOSE_PREFIX_3 "Callback Agent '%s' logged out\n", p->agent);
1496 ast_device_state_changed("Agent/%s", p->agent);
1498 ast_mutex_unlock(&agentlock);
1500 res = ast_safe_sleep(chan, 500);
1501 ast_mutex_unlock(&p->lock);
1503 #ifdef HONOR_MUSIC_CLASS
1504 /* check if the moh class was changed with setmusiconhold */
1505 if (*(chan->musicclass))
1506 strncpy(p->moh, chan->musicclass, sizeof(p->moh) - 1);
1508 ast_moh_start(chan, p->moh);
1509 if (p->loginstart == 0)
1510 time(&p->loginstart);
1511 manager_event(EVENT_FLAG_AGENT, "Agentlogin",
1515 p->agent, chan->name, chan->uniqueid);
1516 if (update_cdr && chan->cdr)
1517 snprintf(chan->cdr->channel, sizeof(chan->cdr->channel), "Agent/%s", p->agent);
1518 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGIN", "%s", chan->name);
1519 if (option_verbose > 2)
1520 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged in (format %s/%s)\n", p->agent,
1521 ast_getformatname(chan->readformat), ast_getformatname(chan->writeformat));
1522 /* Login this channel and wait for it to
1528 check_availability(p, 0);
1529 ast_mutex_unlock(&p->lock);
1530 ast_mutex_unlock(&agentlock);
1531 ast_device_state_changed("Agent/%s", p->agent);
1533 ast_mutex_lock(&p->lock);
1534 if (p->chan != chan)
1536 ast_mutex_unlock(&p->lock);
1537 /* Yield here so other interested threads can kick in. */
1542 ast_mutex_lock(&agentlock);
1543 ast_mutex_lock(&p->lock);
1544 if (p->lastdisc.tv_sec) {
1545 gettimeofday(&tv, NULL);
1546 if ((tv.tv_sec - p->lastdisc.tv_sec) * 1000 +
1547 (tv.tv_usec - p->lastdisc.tv_usec) / 1000 > p->wrapuptime) {
1548 ast_log(LOG_DEBUG, "Wrapup time expired!\n");
1549 memset(&p->lastdisc, 0, sizeof(p->lastdisc));
1553 check_availability(p, 0);
1556 ast_mutex_unlock(&p->lock);
1557 ast_mutex_unlock(&agentlock);
1558 /* Synchronize channel ownership between call to agent and itself. */
1559 ast_mutex_lock( &p->app_lock );
1560 ast_mutex_lock(&p->lock);
1561 p->owning_app = pthread_self();
1562 ast_mutex_unlock(&p->lock);
1564 res = agent_ack_sleep(p);
1566 res = ast_safe_sleep_conditional( chan, 1000,
1567 agent_cont_sleep, p );
1568 ast_mutex_unlock( &p->app_lock );
1569 if ((p->ackcall > 1) && (res == 1)) {
1570 ast_mutex_lock(&agentlock);
1571 ast_mutex_lock(&p->lock);
1572 check_availability(p, 0);
1573 ast_mutex_unlock(&p->lock);
1574 ast_mutex_unlock(&agentlock);
1579 ast_mutex_lock(&p->lock);
1580 if (res && p->owner)
1581 ast_log(LOG_WARNING, "Huh? We broke out when there was still an owner?\n");
1582 /* Log us off if appropriate */
1583 if (p->chan == chan)
1585 p->acknowledged = 0;
1586 logintime = time(NULL) - p->loginstart;
1588 ast_mutex_unlock(&p->lock);
1589 manager_event(EVENT_FLAG_AGENT, "Agentlogoff",
1591 "Logintime: %ld\r\n"
1593 p->agent, logintime, chan->uniqueid);
1594 ast_queue_log("NONE", chan->uniqueid, agent, "AGENTLOGOFF", "%s|%ld", chan->name, logintime);
1595 if (option_verbose > 2)
1596 ast_verbose(VERBOSE_PREFIX_3 "Agent '%s' logged out\n", p->agent);
1597 /* If there is no owner, go ahead and kill it now */
1598 ast_device_state_changed("Agent/%s", p->agent);
1599 if (p->dead && !p->owner) {
1600 ast_mutex_destroy(&p->lock);
1601 ast_mutex_destroy(&p->app_lock);
1606 ast_mutex_unlock(&p->lock);
1611 ast_mutex_unlock(&p->lock);
1612 errmsg = "agent-alreadyon";
1617 ast_mutex_unlock(&p->lock);
1621 ast_mutex_unlock(&agentlock);
1623 if (!res && (max_login_tries==0 || tries < max_login_tries))
1624 res = ast_app_getdata(chan, errmsg, user, sizeof(user) - 1, 0);
1627 LOCAL_USER_REMOVE(u);
1629 res = ast_safe_sleep(chan, 500);
1631 /* AgentLogin() exit */
1632 if (!callbackmode) {
1635 /* AgentCallbackLogin() exit*/
1638 if (login_state > 0) {
1639 pbx_builtin_setvar_helper(chan, "AGENTNUMBER", user);
1640 if (login_state==1) {
1641 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "on");
1642 pbx_builtin_setvar_helper(chan, "AGENTEXTEN", exten);
1645 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "off");
1649 pbx_builtin_setvar_helper(chan, "AGENTSTATUS", "fail");
1651 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 1, chan->cid.cid_num))
1653 /* Do we need to play agent-goodbye now that we will be hanging up? */
1654 if (play_announcement==1) {
1656 res = ast_safe_sleep(chan, 1000);
1657 res = ast_streamfile(chan, agent_goodbye, chan->language);
1659 res = ast_waitstream(chan, "");
1661 res = ast_safe_sleep(chan, 1000);
1664 /* We should never get here if next priority exists when in callbackmode */
1668 static int login_exec(struct ast_channel *chan, void *data)
1670 return __login_exec(chan, data, 0);
1673 static int callback_exec(struct ast_channel *chan, void *data)
1675 return __login_exec(chan, data, 1);
1678 static int agentmonitoroutgoing_exec(struct ast_channel *chan, void *data)
1680 int exitifnoagentid = 0;
1683 char agent[AST_MAX_AGENT], *tmp;
1685 if (strchr(data, 'd'))
1686 exitifnoagentid = 1;
1687 if (strchr(data, 'n'))
1690 if (chan->cid.cid_num) {
1691 char agentvar[AST_MAX_BUF];
1692 snprintf(agentvar, sizeof(agentvar), "%s_%s", GETAGENTBYCALLERID, chan->cid.cid_num);
1693 if ((tmp = pbx_builtin_getvar_helper(NULL, agentvar))) {
1694 struct agent_pvt *p = agents;
1695 strncpy(agent, tmp, sizeof(agent) - 1);
1696 ast_mutex_lock(&agentlock);
1698 if (!strcasecmp(p->agent, tmp)) {
1699 __agent_start_monitoring(chan, p, 1);
1704 ast_mutex_unlock(&agentlock);
1709 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);
1714 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");
1716 /* check if there is n + 101 priority */
1718 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) {
1719 chan->priority+=100;
1720 ast_verbose(VERBOSE_PREFIX_3 "Going to %d priority because there is no callerid or the agentid cannot be found.\n",chan->priority);
1722 else if (exitifnoagentid)
1728 /*--- sip_devicestate: Part of PBX channel interface ---*/
1729 static int agent_devicestate(void *data)
1731 struct agent_pvt *p;
1733 unsigned int groupmatch;
1735 int res = AST_DEVICE_INVALID;
1738 if ((s[0] == '@') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1739 groupmatch = (1 << groupmatch);
1740 } else if ((s[0] == ':') && (sscanf(s + 1, "%d", &groupmatch) == 1)) {
1741 groupmatch = (1 << groupmatch);
1747 /* Check actual logged in agents first */
1748 ast_mutex_lock(&agentlock);
1751 ast_mutex_lock(&p->lock);
1752 if (!p->pending && ((groupmatch && (p->group & groupmatch)) || !strcmp(data, p->agent))) {
1754 if (res != AST_DEVICE_INUSE)
1755 res = AST_DEVICE_BUSY;
1757 if (res == AST_DEVICE_BUSY)
1758 res = AST_DEVICE_INUSE;
1759 if (p->chan || !ast_strlen_zero(p->loginchan)) {
1760 if (res == AST_DEVICE_INVALID)
1761 res = AST_DEVICE_UNKNOWN;
1762 } else if (res == AST_DEVICE_INVALID)
1763 res = AST_DEVICE_UNAVAILABLE;
1765 if (!strcmp(data, p->agent)) {
1766 ast_mutex_unlock(&p->lock);
1770 ast_mutex_unlock(&p->lock);
1773 ast_mutex_unlock(&agentlock);
1779 /* Make sure we can register our sip channel type */
1780 if (ast_channel_register_ex(type, tdesc, capability, agent_request, agent_devicestate)) {
1781 ast_log(LOG_ERROR, "Unable to register channel class %s\n", type);
1784 ast_register_application(app, login_exec, synopsis, descrip);
1785 ast_register_application(app2, callback_exec, synopsis2, descrip2);
1786 ast_register_application(app3, agentmonitoroutgoing_exec, synopsis3, descrip3);
1787 ast_cli_register(&cli_show_agents);
1788 /* Read in the config */
1789 read_agent_config();
1795 read_agent_config();
1801 struct agent_pvt *p;
1802 /* First, take us out of the channel loop */
1803 ast_cli_unregister(&cli_show_agents);
1804 ast_unregister_application(app);
1805 ast_unregister_application(app2);
1806 ast_unregister_application(app3);
1807 ast_channel_unregister(type);
1808 if (!ast_mutex_lock(&agentlock)) {
1809 /* Hangup all interfaces if they have an owner */
1813 ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
1817 ast_mutex_unlock(&agentlock);
1819 ast_log(LOG_WARNING, "Unable to lock the monitor\n");
1828 ast_mutex_lock(&usecnt_lock);
1830 ast_mutex_unlock(&usecnt_lock);
1836 return ASTERISK_GPL_KEY;