Example #1
0
static int system_exec_helper(struct ast_channel *chan, void *data, int failmode)
{
	int res=0;
	struct localuser *u;
	if (!data) {
		ast_log(LOG_WARNING, "System requires an argument(command)\n");
		return failmode;
	}
	LOCAL_USER_ADD(u);
	/* Do our thing here */
	res = ast_safe_system((char *)data);
	if ((res < 0) && (errno != ECHILD)) {
		ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
		res = failmode;
	} else if (res == 127) {
		ast_log(LOG_WARNING, "Unable to execute '%s'\n", (char *)data);
		res = failmode;
	} else {
		if (res < 0)
			res = 0;
		if (res && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) 
			chan->priority+=100;
		res = 0;
	}
	LOCAL_USER_REMOVE(u);
	return res;
}
Example #2
0
static int loopback_exists(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data)
{
	LOOPBACK_COMMON;
	res = ast_exists_extension(chan, newcontext, newexten, newpriority, callerid);
	if (newpattern && !ast_extension_match(newpattern, exten))
		res = 0;
	return res;
}
static int sqliteget_exec(struct ast_channel *chan, void *data)
{
	int arglen;
	char *argv, *varname, *family, *key;
	char dbresult[256];

	arglen = strlen (data);
	argv = alloca (arglen + 1);
	if (!argv)			/* Why would this fail? */
	{
		ast_log (LOG_DEBUG, "Memory allocation failed\n");
		return 0;
	}

	memcpy (argv, data, arglen + 1);

	if (strchr (argv, '=') && strchr (argv, '/'))
	{
		varname = strsep (&argv, "=");
		family = strsep (&argv, "/");
		key = strsep (&argv, "\0");
		if (!varname || !family || !key)
		{
			ast_log (LOG_DEBUG, "Ignoring; Syntax error in argument\n");
			return 0;
		}

		if (option_verbose > 2)
			ast_verbose (VERBOSE_PREFIX_3 "sqliteget: varname=%s, family=%s, key=%s\n", varname, family, key);

		if (!ast_db_sqliteget (family, key, dbresult, sizeof (dbresult) - 1))
		{
			pbx_builtin_setvar_helper (chan, varname, dbresult);
			if (option_verbose > 2)
				ast_verbose (VERBOSE_PREFIX_3 "sqliteget: set variable %s to %s\n", varname, dbresult);
		}
		else
		{
			if (option_verbose > 2)
				ast_verbose (VERBOSE_PREFIX_3 "sqliteget: Value not found in database.\n");
			  /* Send the call to n+101 priority, where n is the current priority */
			if (ast_exists_extension (chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
				chan->priority += 100;
		}

	}
	else
	{
		ast_log (LOG_DEBUG, "Ignoring, no parameters\n");
	}

	return 0;
}
/*! \brief Adds devicestate to local channels */
static int local_devicestate(const char *data)
{
	int is_inuse = 0;
	int res = AST_DEVICE_INVALID;
	char *exten = ast_strdupa(data);
	char *context;
	char *opts;
	struct local_pvt *lp;
	struct ao2_iterator it;

	/* Strip options if they exist */
	opts = strchr(exten, '/');
	if (opts) {
		*opts = '\0';
	}

	context = strchr(exten, '@');
	if (!context) {
		ast_log(LOG_WARNING,
			"Someone used Local/%s somewhere without a @context. This is bad.\n", data);
		return AST_DEVICE_INVALID;
	}
	*context++ = '\0';

	it = ao2_iterator_init(locals, 0);
	for (; (lp = ao2_iterator_next(&it)); ao2_ref(lp, -1)) {
		ao2_lock(lp);
		if (!strcmp(exten, lp->exten)
			&& !strcmp(context, lp->context)) {
			res = AST_DEVICE_NOT_INUSE;
			if (lp->base.owner
				&& ast_test_flag(&lp->base, AST_UNREAL_CARETAKER_THREAD)) {
				is_inuse = 1;
			}
		}
		ao2_unlock(lp);
		if (is_inuse) {
			res = AST_DEVICE_INUSE;
			ao2_ref(lp, -1);
			break;
		}
	}
	ao2_iterator_destroy(&it);

	if (res == AST_DEVICE_INVALID) {
		ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);
		if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
			res = AST_DEVICE_NOT_INUSE;
		}
	}

	return res;
}
Example #5
0
int comeback_goto(struct parked_user *pu, struct parking_lot *lot)
{
	struct ast_channel *chan = pu->chan;
	char *peername_flat = ast_strdupa(pu->parker_dial_string);

	/* Flatten the peername so that it can be used for performing the timeout PBX operations */
	flatten_dial_string(peername_flat);

	if (lot->cfg->comebacktoorigin) {
		if (ast_exists_extension(chan, PARK_DIAL_CONTEXT, peername_flat, 1, NULL)) {
			ast_async_goto(chan, PARK_DIAL_CONTEXT, peername_flat, 1);
			return 0;
		} else {
			ast_log(LOG_ERROR, "Can not start %s at %s,%s,1 because extension does not exist. Terminating call.\n",
				ast_channel_name(chan), PARK_DIAL_CONTEXT, peername_flat);
			return -1;
		}
	}

	if (ast_exists_extension(chan, lot->cfg->comebackcontext, peername_flat, 1, NULL)) {
		ast_async_goto(chan, lot->cfg->comebackcontext, peername_flat, 1);
		return 0;
	}

	if (ast_exists_extension(chan, lot->cfg->comebackcontext, "s", 1, NULL)) {
		ast_verb(2, "Could not start %s at %s,%s,1. Using 's@%s' instead.\n", ast_channel_name(chan),
			lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
		ast_async_goto(chan, lot->cfg->comebackcontext, "s", 1);
		return 0;
	}

	ast_verb(2, "Can not start %s at %s,%s,1 and exten 's@%s' does not exist. Using 's@default'\n",
		ast_channel_name(chan),
		lot->cfg->comebackcontext, peername_flat, lot->cfg->comebackcontext);
	ast_async_goto(chan, "default", "s", 1);

	return 0;
}
Example #6
0
/*!
 * \internal
 * \brief Determine where in the dialplan a call should go
 *
 * \details This uses the username in the request URI to try to match
 * an extension in an endpoint's context in order to route the call.
 *
 * \param rdata The SIP request
 * \param context The context to use
 * \param exten The extension to use
 */
static enum pjsip_status_code get_destination(const pjsip_rx_data *rdata, const char *context, char *exten)
{
	pjsip_uri *ruri = rdata->msg_info.msg->line.req.uri;
	pjsip_sip_uri *sip_ruri;

	if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
		return PJSIP_SC_UNSUPPORTED_URI_SCHEME;
	}

	sip_ruri = pjsip_uri_get_uri(ruri);
	ast_copy_pj_str(exten, &sip_ruri->user, MAX_EXTEN_SIZE);

	if (ast_exists_extension(NULL, context, exten, 1, NULL)) {
		return PJSIP_SC_OK;
	}
	return PJSIP_SC_NOT_FOUND;
}
Example #7
0
static pj_bool_t options_on_rx_request(pjsip_rx_data *rdata)
{
	RAII_VAR(struct ast_sip_endpoint *, endpoint, NULL, ao2_cleanup);
	pjsip_uri *ruri;
	pjsip_sip_uri *sip_ruri;
	char exten[AST_MAX_EXTENSION];

	if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
		return PJ_FALSE;
	}

	if (!(endpoint = ast_pjsip_rdata_get_endpoint(rdata))) {
		return PJ_FALSE;
	}

	ruri = rdata->msg_info.msg->line.req.uri;
	if (!PJSIP_URI_SCHEME_IS_SIP(ruri) && !PJSIP_URI_SCHEME_IS_SIPS(ruri)) {
		send_options_response(rdata, 416);
		return PJ_TRUE;
	}

	sip_ruri = pjsip_uri_get_uri(ruri);
	ast_copy_pj_str(exten, &sip_ruri->user, sizeof(exten));

	/*
	 * We may want to match in the dialplan without any user
	 * options getting in the way.
	 */
	AST_SIP_USER_OPTIONS_TRUNCATE_CHECK(exten);

	if (ast_shutting_down()) {
		/*
		 * Not taking any new calls at this time.
		 * Likely a server availability OPTIONS poll.
		 */
		send_options_response(rdata, 503);
	} else if (!ast_strlen_zero(exten)
		&& !ast_exists_extension(NULL, endpoint->context, exten, 1, NULL)) {
		send_options_response(rdata, 404);
	} else {
		send_options_response(rdata, 200);
	}
	return PJ_TRUE;
}
/*! \brief Adds devicestate to local channels */
static int local_devicestate(const char *data)
{
	char *exten = ast_strdupa(data);
	char *context = NULL, *opts = NULL;
	int res;
	struct local_pvt *lp;
	struct ao2_iterator it;

	if (!(context = strchr(exten, '@'))) {
		ast_log(LOG_WARNING, "Someone used Local/%s somewhere without a @context. This is bad.\n", exten);
		return AST_DEVICE_INVALID;
	}

	*context++ = '\0';

	/* Strip options if they exist */
	if ((opts = strchr(context, '/')))
		*opts = '\0';

	ast_debug(3, "Checking if extension %s@%s exists (devicestate)\n", exten, context);

	res = ast_exists_extension(NULL, context, exten, 1, NULL);
	if (!res)
		return AST_DEVICE_INVALID;

	res = AST_DEVICE_NOT_INUSE;

	it = ao2_iterator_init(locals, 0);
	while ((lp = ao2_iterator_next(&it)) && (res == AST_DEVICE_NOT_INUSE)) {
		if (!strcmp(exten, lp->exten) && !strcmp(context, lp->context) && lp->owner) {
			ao2_lock(lp);
			if (ast_test_flag(lp, LOCAL_LAUNCHED_PBX)) {
				res = AST_DEVICE_INUSE;
			}
			ao2_unlock(lp);
		}
		ao2_ref(lp, -1);
	}
	ao2_iterator_destroy(&it);

	return res;
}
/*! \brief Initiate new call, part of PBX interface
 *         dest is the dial string */
static int local_call(struct ast_channel *ast, const char *dest, int timeout)
{
	struct local_pvt *p = ast_channel_tech_pvt(ast);
	int pvt_locked = 0;

	struct ast_channel *owner = NULL;
	struct ast_channel *chan = NULL;
	int res;
	char *reduced_dest = ast_strdupa(dest);
	char *slash;
	const char *chan_cid;

	if (!p) {
		return -1;
	}

	/* since we are letting go of channel locks that were locked coming into
	 * this function, then we need to give the tech pvt a ref */
	ao2_ref(p, 1);
	ast_channel_unlock(ast);

	ast_unreal_lock_all(&p->base, &chan, &owner);
	pvt_locked = 1;

	if (owner != ast) {
		res = -1;
		goto return_cleanup;
	}

	if (!owner || !chan) {
		res = -1;
		goto return_cleanup;
	}

	ast_unreal_call_setup(owner, chan);

	/*
	 * If the local channel has /n on the end of it, we need to lop
	 * that off for our argument to setting up the CC_INTERFACES
	 * variable.
	 */
	if ((slash = strrchr(reduced_dest, '/'))) {
		*slash = '\0';
	}
	ast_set_cc_interfaces_chanvar(chan, reduced_dest);

	ao2_unlock(p);
	pvt_locked = 0;

	ast_channel_unlock(owner);

	chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid,
		ast_channel_caller(chan)->id.number.str, NULL);
	if (chan_cid) {
		chan_cid = ast_strdupa(chan_cid);
	}
	ast_channel_unlock(chan);

	res = -1;
	switch (p->type) {
	case LOCAL_CALL_ACTION_DIALPLAN:
		if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) {
			ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n",
				p->exten, p->context);
		} else {
			publish_local_bridge_message(p);

			/* Start switch on sub channel */
			res = ast_pbx_start(chan);
		}
		break;
	case LOCAL_CALL_ACTION_BRIDGE:
		publish_local_bridge_message(p);
		ast_answer(chan);
		res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap,
			p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT);
		ao2_ref(p->action.bridge.join, -1);
		p->action.bridge.join = NULL;
		ao2_cleanup(p->action.bridge.swap);
		p->action.bridge.swap = NULL;
		p->action.bridge.features = NULL;
		break;
	case LOCAL_CALL_ACTION_MASQUERADE:
		publish_local_bridge_message(p);
		ast_answer(chan);
		res = ast_channel_move(p->action.masq, chan);
		if (!res) {
			/* Chan is now an orphaned zombie.  Destroy it. */
			ast_hangup(chan);
		}
		p->action.masq = ast_channel_unref(p->action.masq);
		break;
	}
	if (!res) {
		ao2_lock(p);
		ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD);
		ao2_unlock(p);
	}

	/* we already unlocked them, clear them here so the cleanup label won't touch them. */
	owner = ast_channel_unref(owner);
	chan = ast_channel_unref(chan);

return_cleanup:
	if (p) {
		if (pvt_locked) {
			ao2_unlock(p);
		}
		ao2_ref(p, -1);
	}
	if (chan) {
		ast_channel_unlock(chan);
		ast_channel_unref(chan);
	}

	/*
	 * owner is supposed to be == to ast, if it is, don't unlock it
	 * because ast must exit locked
	 */
	if (owner) {
		if (owner != ast) {
			ast_channel_unlock(owner);
			ast_channel_lock(ast);
		}
		ast_channel_unref(owner);
	} else {
		/* we have to exit with ast locked */
		ast_channel_lock(ast);
	}

	return res;
}
Example #10
0
static int conf_run(struct ast_channel *chan, struct ast_conference *conf, int confflags)
{
	struct ast_conference *prev=NULL, *cur;
	struct ast_conf_user *user = malloc(sizeof(struct ast_conf_user));
	int fd;
	struct zt_confinfo ztc;
	struct ast_frame *f;
	struct ast_channel *c;
	struct ast_frame fr;
	int outfd;
	int ms;
	int nfds;
	int res;
	int flags;
	int retryzap;
	int origfd;
	int musiconhold = 0;
	int firstpass = 0;
	int origquiet;
	int ret = -1;
	int x;
	int menu_active = 0;
	int using_pseudo = 0;

	struct ast_app *app;
	char *agifile;
	char *agifiledefault = "conf-background.agi";
	char meetmesecs[30] = "";
	char exitcontext[AST_MAX_EXTENSION] = "";
	int dtmf;

	ZT_BUFFERINFO bi;
	char __buf[CONF_SIZE + AST_FRIENDLY_OFFSET];
	char *buf = __buf + AST_FRIENDLY_OFFSET;
	
	if (!user) {
		ast_log(LOG_ERROR, "Out of memory\n");
		return(ret);
	}
	memset(user, 0, sizeof(struct ast_conf_user));

	user->user_no = 0; /* User number 0 means starting up user! (dead - not in the list!) */

	time(&user->jointime);

	if (conf->locked) {
		/* Sorry, but this confernce is locked! */	
		if (!ast_streamfile(chan, "conf-locked", chan->language))
			ast_waitstream(chan, "");
		goto outrun;
	}
	conf->users++;
	if (confflags & CONFFLAG_MARKEDUSER)
		conf->markedusers++;
      
   	ast_mutex_lock(&conflock);
	if (conf->firstuser == NULL) {
		/* Fill the first new User struct */
		user->user_no = 1;
		user->nextuser = NULL;
		user->prevuser = NULL;
		conf->firstuser = user;
		conf->lastuser = user;
	} else {
		/* Fill the new user struct */	
		user->user_no = conf->lastuser->user_no + 1; 
		user->prevuser = conf->lastuser;
		user->nextuser = NULL;
		if (conf->lastuser->nextuser != NULL) {
			ast_log(LOG_WARNING, "Error in User Management!\n");
			ast_mutex_unlock(&conflock);
			goto outrun;
		} else {
			conf->lastuser->nextuser = user;
			conf->lastuser = user;
		}
	}
	user->chan = chan;
	user->userflags = confflags;
	user->adminflags = 0;
	ast_mutex_unlock(&conflock);
	origquiet = confflags & CONFFLAG_QUIET;
	if (confflags & CONFFLAG_EXIT_CONTEXT) {
		if ((agifile = pbx_builtin_getvar_helper(chan, "MEETME_EXIT_CONTEXT"))) 
			strncpy(exitcontext, agifile, sizeof(exitcontext) - 1);
		else if (!ast_strlen_zero(chan->macrocontext)) 
			strncpy(exitcontext, chan->macrocontext, sizeof(exitcontext) - 1);
		else
			strncpy(exitcontext, chan->context, sizeof(exitcontext) - 1);
	}
	while((confflags & CONFFLAG_WAITMARKED) && (conf->markedusers == 0)) {
		confflags &= ~CONFFLAG_QUIET;
		confflags |= origquiet;
		/* XXX Announce that we're waiting on the conference lead to join */
		if (!(confflags & CONFFLAG_QUIET)) {
			res = ast_streamfile(chan, "vm-dialout", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
		} else
			res = 0;
		/* If we're waiting with hold music, set to silent mode */
		if (!res) {
			confflags |= CONFFLAG_QUIET;
			ast_moh_start(chan, NULL);
			res = ast_safe_sleep_conditional(chan, 60000, confnonzero, conf);
			ast_moh_stop(chan);
		}
		if (res < 0) {
			ast_log(LOG_DEBUG, "Got hangup on '%s' already\n", chan->name);
			goto outrun;
		}
	}
	
	if (!(confflags & CONFFLAG_QUIET) && conf->users == 1) {
		if (!ast_streamfile(chan, "conf-onlyperson", chan->language)) {
			if (ast_waitstream(chan, "") < 0)
				goto outrun;
		} else
			goto outrun;
	}

	/* Set it into linear mode (write) */
	if (ast_set_write_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", chan->name);
		goto outrun;
	}

	/* Set it into linear mode (read) */
	if (ast_set_read_format(chan, AST_FORMAT_SLINEAR) < 0) {
		ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", chan->name);
		goto outrun;
	}
	ast_indicate(chan, -1);
	retryzap = strcasecmp(chan->type, "Zap");
zapretry:
	origfd = chan->fds[0];
	if (retryzap) {
		fd = open("/dev/zap/pseudo", O_RDWR);
		if (fd < 0) {
			ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
			goto outrun;
		}
		using_pseudo = 1;
		/* Make non-blocking */
		flags = fcntl(fd, F_GETFL);
		if (flags < 0) {
			ast_log(LOG_WARNING, "Unable to get flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		if (fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
			ast_log(LOG_WARNING, "Unable to set flags: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		/* Setup buffering information */
		memset(&bi, 0, sizeof(bi));
		bi.bufsize = CONF_SIZE/2;
		bi.txbufpolicy = ZT_POLICY_IMMEDIATE;
		bi.rxbufpolicy = ZT_POLICY_IMMEDIATE;
		bi.numbufs = 4;
		if (ioctl(fd, ZT_SET_BUFINFO, &bi)) {
			ast_log(LOG_WARNING, "Unable to set buffering information: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		x = 1;
		if (ioctl(fd, ZT_SETLINEAR, &x)) {
			ast_log(LOG_WARNING, "Unable to set linear mode: %s\n", strerror(errno));
			close(fd);
			goto outrun;
		}
		nfds = 1;
	} else {
		/* XXX Make sure we're not running on a pseudo channel XXX */
		fd = chan->fds[0];
		nfds = 0;
	}
	memset(&ztc, 0, sizeof(ztc));
	/* Check to see if we're in a conference... */
	ztc.chan = 0;	
	if (ioctl(fd, ZT_GETCONF, &ztc)) {
		ast_log(LOG_WARNING, "Error getting conference\n");
		close(fd);
		goto outrun;
	}
	if (ztc.confmode) {
		/* Whoa, already in a conference...  Retry... */
		if (!retryzap) {
			ast_log(LOG_DEBUG, "Zap channel is in a conference already, retrying with pseudo\n");
			retryzap = 1;
			goto zapretry;
		}
	}
	memset(&ztc, 0, sizeof(ztc));
	/* Add us to the conference */
	ztc.chan = 0;	
	ztc.confno = conf->zapconf;
	if (confflags & CONFFLAG_MONITOR)
		ztc.confmode = ZT_CONF_CONFMON | ZT_CONF_LISTENER;
	else if (confflags & CONFFLAG_TALKER)
		ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER;
	else 
		ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;

	if (ioctl(fd, ZT_SETCONF, &ztc)) {
		ast_log(LOG_WARNING, "Error setting conference\n");
		close(fd);
		goto outrun;
	}
	ast_log(LOG_DEBUG, "Placed channel %s in ZAP conf %d\n", chan->name, conf->zapconf);

	manager_event(EVENT_FLAG_CALL, "MeetmeJoin", 
			"Channel: %s\r\n"
			"Uniqueid: %s\r\n"
			"Meetme: %s\r\n"
			"Usernum: %i\r\n",
			chan->name, chan->uniqueid, conf->confno, user->user_no);

	if (!firstpass && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN)) {
		firstpass = 1;
		if (!(confflags & CONFFLAG_QUIET))
			conf_play(conf, ENTER);
	}

	if (confflags & CONFFLAG_AGI) {

		/* Get name of AGI file to run from $(MEETME_AGI_BACKGROUND)
		  or use default filename of conf-background.agi */

		agifile = pbx_builtin_getvar_helper(chan,"MEETME_AGI_BACKGROUND");
		if (!agifile)
			agifile = agifiledefault;

		if (!strcasecmp(chan->type,"Zap")) {
			/*  Set CONFMUTE mode on Zap channel to mute DTMF tones */
			x = 1;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}
		/* Find a pointer to the agi app and execute the script */
		app = pbx_findapp("agi");
		if (app) {
			ret = pbx_exec(chan, app, agifile, 1);
		} else {
			ast_log(LOG_WARNING, "Could not find application (agi)\n");
			ret = -2;
		}
		if (!strcasecmp(chan->type,"Zap")) {
			/*  Remove CONFMUTE mode on Zap channel */
			x = 0;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}
	} else {
		if (!strcasecmp(chan->type,"Zap") && (confflags & CONFFLAG_STARMENU)) {
			/*  Set CONFMUTE mode on Zap channel to mute DTMF tones when the menu is enabled */
			x = 1;
			ast_channel_setoption(chan,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
		}	
		for(;;) {
			outfd = -1;
			ms = -1;
			c = ast_waitfor_nandfds(&chan, 1, &fd, nfds, NULL, &outfd, &ms);
			
			/* Update the struct with the actual confflags */
			user->userflags = confflags;
			
			/* trying to add moh for single person conf */
			if (confflags & CONFFLAG_MOH) {
				if (conf->users == 1) {
					if (musiconhold == 0) {
						ast_moh_start(chan, NULL);
						musiconhold = 1;
					} 
				} else {
					if (musiconhold) {
						ast_moh_stop(chan);
						musiconhold = 0;
					}
				}
			}
			
			/* Leave if the last marked user left */
			if (conf->markedusers == 0 && confflags & CONFFLAG_MARKEDEXIT) {
				ret = -1;
				break;
			}
	
			/* Check if the admin changed my modes */
			if (user->adminflags) {			
				/* Set the new modes */
				if ((user->adminflags & ADMINFLAG_MUTED) && (ztc.confmode & ZT_CONF_TALKER)) {
					ztc.confmode ^= ZT_CONF_TALKER;
					if (ioctl(fd, ZT_SETCONF, &ztc)) {
						ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
						ret = -1;
						break;
					}
				}
				if (!(user->adminflags & ADMINFLAG_MUTED) && !(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
					ztc.confmode |= ZT_CONF_TALKER;
					if (ioctl(fd, ZT_SETCONF, &ztc)) {
						ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
						ret = -1;
						break;
					}
				}
				if (user->adminflags & ADMINFLAG_KICKME) {
					//You have been kicked.
					if (!ast_streamfile(chan, "conf-kicked", chan->language))
						ast_waitstream(chan, "");
					ret = 0;
					break;
				}
			} else if (!(confflags & CONFFLAG_MONITOR) && !(ztc.confmode & ZT_CONF_TALKER)) {
				ztc.confmode |= ZT_CONF_TALKER;
				if (ioctl(fd, ZT_SETCONF, &ztc)) {
					ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
					ret = -1;
					break;
				}
			}

			if (c) {
				if (c->fds[0] != origfd) {
					if (using_pseudo) {
						/* Kill old pseudo */
						close(fd);
					}
					ast_log(LOG_DEBUG, "Ooh, something swapped out under us, starting over\n");
					retryzap = 0;
					using_pseudo = 0;
					goto zapretry;
				}
				f = ast_read(c);
				if (!f) 
					break;
				if ((f->frametype == AST_FRAME_DTMF) && (confflags & CONFFLAG_EXIT_CONTEXT)) {
					char tmp[2];
					tmp[0] = f->subclass;
					tmp[1] = '\0';
					if (ast_exists_extension(chan, exitcontext, tmp, 1, chan->callerid)) {
						strncpy(chan->context, exitcontext, sizeof(chan->context) - 1);
						strncpy(chan->exten, tmp, sizeof(chan->exten) - 1);
						chan->priority = 0;
						ret = 0;
						break;
					}
				} else if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#') && (confflags & CONFFLAG_POUNDEXIT)) {
					ret = 0;
					break;
				} else if (((f->frametype == AST_FRAME_DTMF) && (f->subclass == '*') && (confflags & CONFFLAG_STARMENU)) || ((f->frametype == AST_FRAME_DTMF) && menu_active)) {
					if (musiconhold) {
			   			ast_moh_stop(chan);
					}
					if ((confflags & CONFFLAG_ADMIN)) {
						/* Admin menu */
						if (!menu_active) {
							menu_active = 1;
							/* Record this sound! */
							if (!ast_streamfile(chan, "conf-adminmenu", chan->language))
								dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
							else
								dtmf = 0;
						} else 
							dtmf = f->subclass;
						if (dtmf) {
							switch(dtmf) {
								case '1': /* Un/Mute */
									menu_active = 0;
		 							if (ztc.confmode & ZT_CONF_TALKER) {
	 						       		ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
	 						       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
									} else {
										ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
										confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
									}
									if (ioctl(fd, ZT_SETCONF, &ztc)) {
										ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
										ret = -1;
										break;
									}
									if (ztc.confmode & ZT_CONF_TALKER) {
										if (!ast_streamfile(chan, "conf-unmuted", chan->language))
											ast_waitstream(chan, "");
									} else {
										if (!ast_streamfile(chan, "conf-muted", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								case '2': /* Un/Lock the Conference */
									menu_active = 0;
									if (conf->locked) {
										conf->locked = 0;
										if (!ast_streamfile(chan, "conf-unlockednow", chan->language))
											ast_waitstream(chan, "");
									} else {
										conf->locked = 1;
										if (!ast_streamfile(chan, "conf-lockednow", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								default:
									menu_active = 0;
									/* Play an error message! */
									if (!ast_streamfile(chan, "conf-errormenu", chan->language))
										ast_waitstream(chan, "");
									break;
							}
						}
					} else {
						/* User menu */
						if (!menu_active) {
							menu_active = 1;
							/* Record this sound! */
							if (!ast_streamfile(chan, "conf-usermenu", chan->language))
								dtmf = ast_waitstream(chan, AST_DIGIT_ANY);
							else
								dtmf = 0;
						} else 
							dtmf = f->subclass;
						if (dtmf) {
							switch(dtmf) {
								case '1': /* Un/Mute */
									menu_active = 0;
		 							if (ztc.confmode & ZT_CONF_TALKER) {
	 						       		ztc.confmode = ZT_CONF_CONF | ZT_CONF_LISTENER;
	 						       		confflags |= CONFFLAG_MONITOR ^ CONFFLAG_TALKER;
									} else if (!(user->adminflags & ADMINFLAG_MUTED)) {
										ztc.confmode = ZT_CONF_CONF | ZT_CONF_TALKER | ZT_CONF_LISTENER;
										confflags ^= CONFFLAG_MONITOR | CONFFLAG_TALKER;
									}
									if (ioctl(fd, ZT_SETCONF, &ztc)) {
										ast_log(LOG_WARNING, "Error setting conference - Un/Mute \n");
										ret = -1;
										break;
									}
									if (ztc.confmode & ZT_CONF_TALKER) {
										if (!ast_streamfile(chan, "conf-unmuted", chan->language))
											ast_waitstream(chan, "");
									} else {
										if (!ast_streamfile(chan, "conf-muted", chan->language))
											ast_waitstream(chan, "");
									}
									break;
								default:
									menu_active = 0;
									/* Play an error message! */
									if (!ast_streamfile(chan, "conf-errormenu", chan->language))
										ast_waitstream(chan, "");
									break;
							}
						}
					}
					if (musiconhold) {
			   			ast_moh_start(chan, NULL);
					}
				} else if (using_pseudo) {
					if (f->frametype == AST_FRAME_VOICE) {
						if (f->subclass == AST_FORMAT_SLINEAR) {
							/* Carefully write */
							careful_write(fd, f->data, f->datalen);
						} else
							ast_log(LOG_WARNING, "Huh?  Got a non-linear (%d) frame in the conference\n", f->subclass);
					}
				}
				ast_frfree(f);
			} else if (outfd > -1) {
				res = read(outfd, buf, CONF_SIZE);
				if (res > 0) {
					memset(&fr, 0, sizeof(fr));
					fr.frametype = AST_FRAME_VOICE;
					fr.subclass = AST_FORMAT_SLINEAR;
					fr.datalen = res;
					fr.samples = res/2;
					fr.data = buf;
					fr.offset = AST_FRIENDLY_OFFSET;
					if (ast_write(chan, &fr) < 0) {
						ast_log(LOG_WARNING, "Unable to write frame to channel: %s\n", strerror(errno));
						/* break; */
					}
				} else 
					ast_log(LOG_WARNING, "Failed to read frame: %s\n", strerror(errno));
			}
		}
	}
	if (using_pseudo)
		close(fd);
	else {
		/* Take out of conference */
		/* Add us to the conference */
		ztc.chan = 0;	
		ztc.confno = 0;
		ztc.confmode = 0;
		if (ioctl(fd, ZT_SETCONF, &ztc)) {
			ast_log(LOG_WARNING, "Error setting conference\n");
		}
	}
	if (!(confflags & CONFFLAG_QUIET) && !(confflags & CONFFLAG_MONITOR) && !(confflags & CONFFLAG_ADMIN))
		conf_play(conf, LEAVE);

outrun:
	ast_mutex_lock(&conflock);
	if (user->user_no) { /* Only cleanup users who really joined! */
		manager_event(EVENT_FLAG_CALL, "MeetmeLeave", 
			"Channel: %s\r\n"
			"Uniqueid: %s\r\n"
			"Meetme: %s\r\n"
			"Usernum: %i\r\n",
			chan->name, chan->uniqueid, conf->confno, user->user_no);
		prev = NULL;
		conf->users--;
		if (confflags & CONFFLAG_MARKEDUSER) 
			conf->markedusers--;
		cur = confs;
		if (!conf->users) {
			/* No more users -- close this one out */
			while(cur) {
				if (cur == conf) {
					if (prev)
						prev->next = conf->next;
					else
						confs = conf->next;
					break;
				}
				prev = cur;
				cur = cur->next;
			}
			if (!cur) 
				ast_log(LOG_WARNING, "Conference not found\n");
			if (conf->chan)
				ast_hangup(conf->chan);
			else
				close(conf->fd);
			free(conf);
		} else {
			/* Remove the user struct */ 
			if (user == conf->firstuser) {
				if (user->nextuser) {
					/* There is another entry */
					user->nextuser->prevuser = NULL;
				} else {
					/* We are the only entry */
					conf->lastuser = NULL;
				}
				/* In either case */
				conf->firstuser = user->nextuser;
			} else if (user == conf->lastuser){
				if (user->prevuser)
					user->prevuser->nextuser = NULL;
				else
					ast_log(LOG_ERROR, "Bad bad bad!  We're the last, not the first, but nobody before us??\n");
				conf->lastuser = user->prevuser;
			} else {
				if (user->nextuser)
					user->nextuser->prevuser = user->prevuser;
				else
					ast_log(LOG_ERROR, "Bad! Bad! Bad! user->nextuser is NULL but we're not the end!\n");
				if (user->prevuser)
					user->prevuser->nextuser = user->nextuser;
				else
					ast_log(LOG_ERROR, "Bad! Bad! Bad! user->prevuser is NULL but we're not the beginning!\n");
			}
		}
		/* Return the number of seconds the user was in the conf */
		snprintf(meetmesecs, sizeof(meetmesecs), "%i", (int) (time(NULL) - user->jointime));
		pbx_builtin_setvar_helper(chan, "MEETMESECS", meetmesecs);
	}
	free(user);
	ast_mutex_unlock(&conflock);
	return ret;
}
Example #11
0
static int _macro_exec(struct ast_channel *chan, const char *data, int exclusive)
{
	const char *s;
	char *tmp;
	char *cur, *rest;
	char *macro;
	char fullmacro[80];
	char varname[80];
	char runningapp[80], runningdata[1024];
	char *oldargs[MAX_ARGS + 1] = { NULL, };
	int argc, x;
	int res=0;
	char oldexten[256]="";
	int oldpriority, gosub_level = 0;
	char pc[80], depthc[12];
	char oldcontext[AST_MAX_CONTEXT] = "";
	const char *inhangupc;
	int offset, depth = 0, maxdepth = 7;
	int setmacrocontext=0;
	int autoloopflag, inhangup = 0;
	struct ast_str *tmp_subst = NULL;
  
	char *save_macro_exten;
	char *save_macro_context;
	char *save_macro_priority;
	char *save_macro_offset;
	struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
		return -1;
	}

	do {
		if (macro_store) {
			break;
		}
		if (!(macro_store = ast_datastore_alloc(&macro_ds_info, NULL))) {
			ast_log(LOG_WARNING, "Unable to allocate new datastore.\n");
			break;
		}
		/* Just the existence of this datastore is enough. */
		macro_store->inheritance = DATASTORE_INHERIT_FOREVER;
		ast_channel_datastore_add(chan, macro_store);
	} while (0);

	/* does the user want a deeper rabbit hole? */
	ast_channel_lock(chan);
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_RECURSION"))) {
		sscanf(s, "%30d", &maxdepth);
	}
	
	/* Count how many levels deep the rabbit hole goes */
	if ((s = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH"))) {
		sscanf(s, "%30d", &depth);
	}
	
	/* Used for detecting whether to return when a Macro is called from another Macro after hangup */
	if (strcmp(ast_channel_exten(chan), "h") == 0)
		pbx_builtin_setvar_helper(chan, "MACRO_IN_HANGUP", "1");
	
	if ((inhangupc = pbx_builtin_getvar_helper(chan, "MACRO_IN_HANGUP"))) {
		sscanf(inhangupc, "%30d", &inhangup);
	}
	ast_channel_unlock(chan);

	if (depth >= maxdepth) {
		ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
		return 0;
	}
	snprintf(depthc, sizeof(depthc), "%d", depth + 1);

	tmp = ast_strdupa(data);
	rest = tmp;
	macro = strsep(&rest, ",");
	if (ast_strlen_zero(macro)) {
		ast_log(LOG_WARNING, "Invalid macro name specified\n");
		return 0;
	}

	snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
	if (!ast_exists_extension(chan, fullmacro, "s", 1,
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		if (!ast_context_find(fullmacro)) 
			ast_log(LOG_WARNING, "No such context '%s' for macro '%s'. Was called by %s@%s\n", fullmacro, macro, ast_channel_exten(chan), ast_channel_context(chan));
		else
			ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
		return 0;
	}

	/* If we are to run the macro exclusively, take the mutex */
	if (exclusive) {
		ast_debug(1, "Locking macrolock for '%s'\n", fullmacro);
		ast_autoservice_start(chan);
		if (ast_context_lockmacro(fullmacro)) {
			ast_log(LOG_WARNING, "Failed to lock macro '%s' as in-use\n", fullmacro);
			ast_autoservice_stop(chan);
			return 0;
		}
		ast_autoservice_stop(chan);
	}

	if (!(tmp_subst = ast_str_create(16))) {
		return -1;
	}

	/* Save old info */
	oldpriority = ast_channel_priority(chan);
	ast_copy_string(oldexten, ast_channel_exten(chan), sizeof(oldexten));
	ast_copy_string(oldcontext, ast_channel_context(chan), sizeof(oldcontext));
	if (ast_strlen_zero(ast_channel_macrocontext(chan))) {
		ast_channel_macrocontext_set(chan, ast_channel_context(chan));
		ast_channel_macroexten_set(chan, ast_channel_exten(chan));
		ast_channel_macropriority_set(chan, ast_channel_priority(chan));
		setmacrocontext=1;
	}
	argc = 1;
	/* Save old macro variables */
	save_macro_exten = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_EXTEN"));
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);

	save_macro_context = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT"));
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);

	save_macro_priority = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY"));
	snprintf(pc, sizeof(pc), "%d", oldpriority);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
  
	save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);

	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

	/* Setup environment for new run */
	ast_channel_exten_set(chan, "s");
	ast_channel_context_set(chan, fullmacro);
	ast_channel_priority_set(chan, 1);

	ast_channel_lock(chan);
	while((cur = strsep(&rest, ",")) && (argc < MAX_ARGS)) {
		const char *argp;
  		/* Save copy of old arguments if we're overwriting some, otherwise
	   	let them pass through to the other macro */
  		snprintf(varname, sizeof(varname), "ARG%d", argc);
		if ((argp = pbx_builtin_getvar_helper(chan, varname))) {
			oldargs[argc] = ast_strdup(argp);
		}
		pbx_builtin_setvar_helper(chan, varname, cur);
		argc++;
	}
	ast_channel_unlock(chan);
	autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
	while (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
		struct ast_context *c;
		struct ast_exten *e;
		int foundx;
		runningapp[0] = '\0';
		runningdata[0] = '\0';

		/* What application will execute? */
		if (ast_rdlock_contexts()) {
			ast_log(LOG_WARNING, "Failed to lock contexts list\n");
		} else {
			for (c = ast_walk_contexts(NULL), e = NULL; c; c = ast_walk_contexts(c)) {
				if (!strcmp(ast_get_context_name(c), ast_channel_context(chan))) {
					if (ast_rdlock_context(c)) {
						ast_log(LOG_WARNING, "Unable to lock context?\n");
					} else {
						e = find_matching_priority(c, ast_channel_exten(chan), ast_channel_priority(chan),
							S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL));
						if (e) { /* This will only be undefined for pbx_realtime, which is majorly broken. */
							ast_copy_string(runningapp, ast_get_extension_app(e), sizeof(runningapp));
							ast_copy_string(runningdata, ast_get_extension_app_data(e), sizeof(runningdata));
						}
						ast_unlock_context(c);
					}
					break;
				}
			}
		}
		ast_unlock_contexts();

		/* Reset the macro depth, if it was changed in the last iteration */
		pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

		res = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan),
			S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
			&foundx, 1);
		if (res) {
			/* Something bad happened, or a hangup has been requested. */
			if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
		    	(res == '*') || (res == '#')) {
				/* Just return result as to the previous application as if it had been dialed */
				ast_debug(1, "Oooh, got something to jump out with ('%c')!\n", res);
				break;
			}
			switch(res) {
			case MACRO_EXIT_RESULT:
				res = 0;
				goto out;
			default:
				ast_debug(2, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan), macro);
				goto out;
			}
		}

		ast_debug(1, "Executed application: %s\n", runningapp);

		if (!strcasecmp(runningapp, "GOSUB")) {
			gosub_level++;
			ast_debug(1, "Incrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "GOSUBIF")) {
			char *cond, *app_arg;
			char *app2;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			app2 = ast_str_buffer(tmp_subst);
			cond = strsep(&app2, "?");
			app_arg = strsep(&app2, ":");
			if (pbx_checkcondition(cond)) {
				if (!ast_strlen_zero(app_arg)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			} else {
				if (!ast_strlen_zero(app2)) {
					gosub_level++;
					ast_debug(1, "Incrementing gosub_level\n");
				}
			}
		} else if (!strcasecmp(runningapp, "RETURN")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strcasecmp(runningapp, "STACKPOP")) {
			gosub_level--;
			ast_debug(1, "Decrementing gosub_level\n");
		} else if (!strncasecmp(runningapp, "EXEC", 4)) {
			/* Must evaluate args to find actual app */
			char *tmp2, *tmp3 = NULL;
			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
			tmp2 = ast_str_buffer(tmp_subst);
			if (!strcasecmp(runningapp, "EXECIF")) {
				if ((tmp3 = strchr(tmp2, '|'))) {
					*tmp3++ = '\0';
				}
				if (!pbx_checkcondition(tmp2)) {
					tmp3 = NULL;
				}
			} else {
				tmp3 = tmp2;
			}

			if (tmp3) {
				ast_debug(1, "Last app: %s\n", tmp3);
			}

			if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
				gosub_level++;
				ast_debug(1, "Incrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "RETURN", 6)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			} else if (tmp3 && !strncasecmp(tmp3, "STACKPOP", 8)) {
				gosub_level--;
				ast_debug(1, "Decrementing gosub_level\n");
			}
		}

		if (gosub_level == 0 && strcasecmp(ast_channel_context(chan), fullmacro)) {
			ast_verb(2, "Channel '%s' jumping out of macro '%s'\n", ast_channel_name(chan), macro);
			break;
		}

		/* don't stop executing extensions when we're in "h" */
		if (ast_check_hangup(chan) && !inhangup) {
			ast_debug(1, "Extension %s, macroexten %s, priority %d returned normally even though call was hung up\n", ast_channel_exten(chan), ast_channel_macroexten(chan), ast_channel_priority(chan));
			goto out;
		}
		ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
  	}
	out:

	/* Don't let the channel change now. */
	ast_channel_lock(chan);

	/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
	snprintf(depthc, sizeof(depthc), "%d", depth);
	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
	ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);

  	for (x = 1; x < argc; x++) {
  		/* Restore old arguments and delete ours */
		snprintf(varname, sizeof(varname), "ARG%d", x);
  		if (oldargs[x]) {
			pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
			ast_free(oldargs[x]);
		} else {
			pbx_builtin_setvar_helper(chan, varname, NULL);
		}
  	}

	/* Restore macro variables */
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
	if (save_macro_exten)
		ast_free(save_macro_exten);
	if (save_macro_context)
		ast_free(save_macro_context);
	if (save_macro_priority)
		ast_free(save_macro_priority);

	if (setmacrocontext) {
		ast_channel_macrocontext_set(chan, "");
		ast_channel_macroexten_set(chan, "");
		ast_channel_macropriority_set(chan, 0);
	}

	if (!strcasecmp(ast_channel_context(chan), fullmacro)) {
		const char *offsets;

  		/* If we're leaving the macro normally, restore original information */
		ast_channel_priority_set(chan, oldpriority);
		ast_channel_context_set(chan, oldcontext);
		ast_channel_exten_set(chan, oldexten);
		if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
			/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
			normally if there is any problem */
			if (sscanf(offsets, "%30d", &offset) == 1) {
				if (ast_exists_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
					ast_channel_priority(chan) + offset + 1,
					S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
					ast_channel_priority_set(chan, ast_channel_priority(chan) + offset);
				}
			}
		}
	}

	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
	if (save_macro_offset)
		ast_free(save_macro_offset);

	/* Unlock the macro */
	if (exclusive) {
		ast_debug(1, "Unlocking macrolock for '%s'\n", fullmacro);
		if (ast_context_unlockmacro(fullmacro)) {
			ast_log(LOG_ERROR, "Failed to unlock macro '%s' - that isn't good\n", fullmacro);
			res = 0;
		}
	}
	ast_channel_unlock(chan);
	ast_free(tmp_subst);

	return res;
}
Example #12
0
static int nv_background_detect_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	struct ast_module_user *u;
	char tmp[256] = "\0";
	char *p = NULL;
	char *filename = NULL;
	char *options = NULL;
	char *silstr = NULL;
	char *minstr = NULL;
	char *maxstr = NULL;
	struct ast_frame *fr = NULL;
	struct ast_frame *fr2 = NULL;
	int notsilent = 0;
	struct timeval start = {0, 0}, end = {0, 0};
	int sildur = 1000;
	int mindur = 100;
	int maxdur = -1;
	int skipanswer = 0;
	int noextneeded = 0;
	int ignoredtmf = 0;
	int ignorefax = 0;
	int ignoretalk = 0;
	int x = 0;
	int origrformat = 0;
	int features = 0;
	struct ast_dsp *dsp = NULL;
	
	pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "FAXEXTEN", "");
	pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "TALK_DETECTED", "");
	
	if (!data || ast_strlen_zero((char *)data)) {
		ast_log(LOG_WARNING, "NVBackgroundDetect requires an argument (filename)\n");
		return -1;
	}	
	
	strncpy(tmp, (char *)data, sizeof(tmp)-1);
	p = tmp;
	
	filename = strsep(&p, "|");
	options = strsep(&p, "|");
	silstr = strsep(&p, "|");
	minstr = strsep(&p, "|");	
	maxstr = strsep(&p, "|");	
	
	if (options) {
		if (strchr(options, 'n'))
			skipanswer = 1;
		if (strchr(options, 'x'))
			noextneeded = 1;
		if (strchr(options, 'd'))
			ignoredtmf = 1;
		if (strchr(options, 'f'))
			ignorefax = 1;
		if (strchr(options, 't'))
			ignoretalk = 1;
	}
	
	if (silstr) {
		if ((sscanf(silstr, "%d", &x) == 1) && (x > 0))
			sildur = x;
	}
	
	if (minstr) {
		if ((sscanf(minstr, "%d", &x) == 1) && (x > 0))
			mindur = x;
	}
	
	if (maxstr) {
		if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0))
			maxdur = x;
	}
	
	ast_log(LOG_DEBUG, "Preparing detect of '%s' (sildur=%dms, mindur=%dms, maxdur=%dms)\n", 
						tmp, sildur, mindur, maxdur);
						
	u = ast_module_user_add(chan);
	if (chan->_state != AST_STATE_UP && !skipanswer) {
		/* Otherwise answer unless we're supposed to send this while on-hook */
		res = ast_answer(chan);
	}
	if (!res) {
		origrformat = chan->readformat;
		if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) 
			ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
	}
	if (!(dsp = ast_dsp_new())) {
		ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
		res = -1;
	}

	if (dsp) {	
		if (!ignoretalk)
			; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */
		if (!ignorefax)
			features |= DSP_FEATURE_FAX_DETECT;
		//if (!ignoredtmf)
			features |= DSP_FEATURE_DTMF_DETECT;
			
		ast_dsp_set_threshold(dsp, 256);
		ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF);
		ast_dsp_digitmode(dsp, DSP_DIGITMODE_DTMF);
	}
	
	if (!res) {
		ast_stopstream(chan);
		res = ast_streamfile(chan, tmp, chan->language);
		if (!res) {
			while(chan->stream) {
				res = ast_sched_wait(chan->sched);
				if ((res < 0) && !chan->timingfunc) {
					res = 0;
					break;
				}
				if (res < 0)
					res = 1000;
				res = ast_waitfor(chan, res);
				if (res < 0) {
					ast_log(LOG_WARNING, "Waitfor failed on %s\n", chan->name);
					break;
				} else if (res > 0) {
					fr = ast_read(chan);
					if (!fr) {
						ast_log(LOG_DEBUG, "Got hangup\n");
						res = -1;
						break;
					}
					
					fr2 = ast_dsp_process(chan, dsp, fr);
					if (!fr2) {
						ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n");
						fr2 = fr;
					} 
					
					if (fr2->frametype == AST_FRAME_DTMF) {
						if (fr2->subclass == 'f' && !ignorefax) {
							/* Fax tone -- Handle and return NULL */
							ast_log(LOG_DEBUG, "Fax detected on %s\n", chan->name);
							if (strcmp(chan->exten, "fax")) {
								ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", chan->name);
								pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1");
								pbx_builtin_setvar_helper(chan,"FAXEXTEN",chan->exten);								
								if (ast_exists_extension(chan, chan->context, "fax", 1, chan->CALLERID_FIELD)) {
									/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
									strncpy(chan->exten, "fax", sizeof(chan->exten)-1);
									chan->priority = 0;									
								} else
									ast_log(LOG_WARNING, "Fax detected, but no fax extension\n");
							} else
								ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n");

							res = 0;
							ast_frfree(fr);
							break;
						} else if (!ignoredtmf) {
							char t[2];
							t[0] = fr2->subclass;
							t[1] = '\0';
							ast_log(LOG_DEBUG, "DTMF detected on %s\n", chan->name);
							if (noextneeded || ast_canmatch_extension(chan, chan->context, t, 1, chan->CALLERID_FIELD)) {
								pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1");
								/* They entered a valid extension, or might be anyhow */
								if (noextneeded) {
									ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n");
									res = 0;
								} else {
									ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n");
									res = fr2->subclass;
								}
								ast_frfree(fr);
								break;
							} else
								ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n");
						}
					} else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) {
						int totalsilence;
						int ms;
						res = ast_dsp_silence(dsp, fr, &totalsilence);
						if (res && (totalsilence > sildur)) {
							/* We've been quiet a little while */
							if (notsilent) {
								/* We had heard some talking */
								gettimeofday(&end, NULL);
								ms = (end.tv_sec - start.tv_sec) * 1000;
								ms += (end.tv_usec - start.tv_usec) / 1000;
								ms -= sildur;
								if (ms < 0)
									ms = 0;
								if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) {
									char ms_str[10];
									ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
									ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", chan->name);

									/* Save detected talk time (in milliseconds) */ 
									sprintf(ms_str, "%d", ms);	
									pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);
									
									if (ast_exists_extension(chan, chan->context, "talk", 1, chan->CALLERID_FIELD)) {
										strncpy(chan->exten, "talk", sizeof(chan->exten) - 1);
										chan->priority = 0;
									} else
										ast_log(LOG_WARNING, "Talk detected, but no talk extension\n");
									res = 0;
									ast_frfree(fr);
									break;
								} else
									ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
								notsilent = 0;
							}
						} else {
							if (!notsilent) {
								/* Heard some audio, mark the begining of the token */
								gettimeofday(&start, NULL);
								ast_log(LOG_DEBUG, "Start of voice token!\n");
								notsilent = 1;
							}
						}						
					}
					ast_frfree(fr);
				}
				ast_sched_runq(chan->sched);
			}
			ast_stopstream(chan);
		} else {
			ast_log(LOG_WARNING, "ast_streamfile failed on %s for %s\n", chan->name, (char *)data);
			res = 0;
		}
	} else
		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
	
	if (res > -1) {
		if (origrformat && ast_set_read_format(chan, origrformat)) {
			ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", 
				chan->name, ast_getformatname(origrformat));
		}
	}
	
	if (dsp)
		ast_dsp_free(dsp);
	
	ast_module_user_remove(u);
	
	return res;
}
Example #13
0
static void phone_check_exception(struct phone_pvt *i)
{
	int offhook=0;
	char digit[2] = {0 , 0};
	union telephony_exception phonee;
	/* XXX Do something XXX */
#if 0
	ast_log(LOG_DEBUG, "Exception!\n");
#endif
	phonee.bytes = ioctl(i->fd, PHONE_EXCEPTION);
	if (phonee.bits.dtmf_ready)  {
		digit[0] = ioctl(i->fd, PHONE_GET_DTMF_ASCII);
		if (i->mode == MODE_DIALTONE) {
			ioctl(i->fd, PHONE_PLAY_STOP);
			ioctl(i->fd, PHONE_REC_STOP);
			ioctl(i->fd, PHONE_CPT_STOP);
			i->dialtone = 0;
			if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
				strncat(i->ext, digit, sizeof(i->ext) - strlen(i->ext) - 1);
			if (ast_exists_extension(NULL, i->context, i->ext, 1, i->callerid)) {
				/* It's a valid extension in its context, get moving! */
				phone_new(i, AST_STATE_RING, i->context);
				/* No need to restart monitor, we are the monitor */
				if (i->owner) {
					ast_mutex_lock(&usecnt_lock);
					usecnt--;
					ast_mutex_unlock(&usecnt_lock);
					ast_update_use_count();
				}
			} else if (!ast_canmatch_extension(NULL, i->context, i->ext, 1, i->callerid)) {
				/* There is nothing in the specified extension that can match anymore.
				   Try the default */
				if (ast_exists_extension(NULL, "default", i->ext, 1, i->callerid)) {
					/* Check the default, too... */
					phone_new(i, AST_STATE_RING, "default");
					if (i->owner) {
						ast_mutex_lock(&usecnt_lock);
						usecnt--;
						ast_mutex_unlock(&usecnt_lock);
						ast_update_use_count();
					}
					/* XXX This should probably be justified better XXX */
				}  else if (!ast_canmatch_extension(NULL, "default", i->ext, 1, i->callerid)) {
					/* It's not a valid extension, give a busy signal */
					if (option_debug)
						ast_log(LOG_DEBUG, "%s can't match anything in %s or default\n", i->ext, i->context);
					ioctl(i->fd, PHONE_BUSY);
					i->cpt = 1;
				}
			}
#if 0
			ast_verbose("Extension is %s\n", i->ext);
#endif
		}
	}
	if (phonee.bits.hookstate) {
		offhook = ioctl(i->fd, PHONE_HOOKSTATE);
		if (offhook) {
			if (i->mode == MODE_IMMEDIATE) {
				phone_new(i, AST_STATE_RING, i->context);
			} else if (i->mode == MODE_DIALTONE) {
				ast_mutex_lock(&usecnt_lock);
				usecnt++;
				ast_mutex_unlock(&usecnt_lock);
				ast_update_use_count();
				/* Reset the extension */
				i->ext[0] = '\0';
				/* Play the dialtone */
				i->dialtone++;
				ioctl(i->fd, PHONE_PLAY_STOP);
				ioctl(i->fd, PHONE_PLAY_CODEC, ULAW);
				ioctl(i->fd, PHONE_PLAY_START);
				i->lastformat = -1;
			}
		} else {
			if (i->dialtone) {
				ast_mutex_lock(&usecnt_lock);
				usecnt--;
				ast_mutex_unlock(&usecnt_lock);
				ast_update_use_count();
			}
			memset(i->ext, 0, sizeof(i->ext));
			if (i->cpt)
			{
				ioctl(i->fd, PHONE_CPT_STOP);
				i->cpt = 0;
			}
			ioctl(i->fd, PHONE_PLAY_STOP);
			ioctl(i->fd, PHONE_REC_STOP);
			i->dialtone = 0;
			i->lastformat = -1;
		}
	}
	if (phonee.bits.pstn_ring) {
		ast_verbose("Unit is ringing\n");
		phone_new(i, AST_STATE_RING, i->context);
	}
	if (phonee.bits.caller_id)
		ast_verbose("We have caller ID\n");
	
	
}
Example #14
0
static struct ast_frame *i4l_read(struct ast_modem_pvt *p)
{
    unsigned char result[256];
    short *b;
    struct ast_frame *f=NULL;
    int res;
    int x;
    if (p->ministate == STATE_COMMAND) {
        /* Read the first two bytes, first, in case it's a control message */
        res = read(p->fd, result, 2);
        if (res < 2) {
            /* short read, means there was a hangup? */
            /* (or is this also possible without hangup?) */
            /* Anyway, reading from unitialized buffers is a bad idea anytime. */
            if (errno == EAGAIN)
                return i4l_handle_escape(p, 0);
            return NULL;
        }
        if (result[0] == CHAR_DLE) {
            return i4l_handle_escape(p, result[1]);

        } else {
            if ((result[0] == '\n') || (result[0] == '\r'))
                return i4l_handle_escape(p, 0);
            /* Read the rest of the line */
            fgets(result + 2, sizeof(result) - 2, p->f);
            ast_modem_trim(result);
            if (!strcasecmp(result, "VCON")) {
                /* If we're in immediate mode, reply now */
                /*				if (p->mode == MODEM_MODE_IMMEDIATE) */
                return i4l_handle_escape(p, 'X');
            } else if (!strcasecmp(result, "BUSY")) {
                /* Same as a busy signal */
                return i4l_handle_escape(p, 'b');
            } else if (!strncasecmp(result, "CALLER NUMBER: ", 15 )) {
                strncpy(p->cid_num, result + 15, sizeof(p->cid_num)-1);
                return i4l_handle_escape(p, 0);
            } else if (!strcasecmp(result, "RINGING")) {
                if (option_verbose > 2)
                    ast_verbose(VERBOSE_PREFIX_3 "%s is ringing...\n", p->dev);
                return i4l_handle_escape(p, 'I');
            } else if (!strncasecmp(result, "RUNG", 4)) {
                /* PM2002: the line was hung up before we picked it up, bye bye */
                if (option_verbose > 2)
                    ast_verbose(VERBOSE_PREFIX_3 "%s was hung up on before we answered\n", p->dev);
                return NULL;
            } else if (!strncasecmp(result, "RING", 4)) {
                if (result[4]=='/')
                    strncpy(p->dnid, result + 5, sizeof(p->dnid)-1);
                return i4l_handle_escape(p, 'R');
            } else if (!strcasecmp(result, "NO CARRIER")) {
                if (option_verbose > 2)
                    ast_verbose(VERBOSE_PREFIX_3 "%s hung up on\n", p->dev);
                return NULL;
            } else if (!strcasecmp(result, "NO DIALTONE")) {
                /* There's no dialtone, so the line isn't working */
                ast_log(LOG_WARNING, "Device '%s' lacking dialtone\n", p->dev);
                return NULL;
            }
            if (option_debug)
                ast_log(LOG_DEBUG, "Modem said '%s'\n", result);
            return i4l_handle_escape(p, 0);
        }
    } else {
        /* We have to be more efficient in voice mode */
        b = (short *)(p->obuf + p->obuflen);
        while (p->obuflen/2 < 240) {
            /* Read ahead the full amount */
            res = read(p->fd, result, 240 - p->obuflen/2);
            if (res < 1) {
                /* If there's nothing there, just continue on */
                if (errno == EAGAIN)
                    return i4l_handle_escape(p, 0);
                ast_log(LOG_WARNING, "Read failed: %s\n", strerror(errno));
                return NULL;
            }

            for (x=0; x<res; x++) {
                /* Process all the bytes that we've read */
                switch(result[x]) {
                case CHAR_DLE:
#if 0
                    ast_log(LOG_DEBUG, "Ooh, an escape at %d...\n", x);
#endif
                    if (!p->escape) {
                        /* Note that next value is
                           an escape, and continue. */
                        p->escape++;
                        break;
                    } else {
                        /* Send as is -- fallthrough */
                        p->escape = 0;
                    }
                default:
                    if (p->escape) {
                        ast_log(LOG_DEBUG, "Value of escape is %c (%d)...\n", result[x] < 32 ? '^' : result[x], result[x]);
                        p->escape = 0;
                        if (f)
                            ast_log(LOG_WARNING, "Warning: Dropped a signal frame\n");
                        f = i4l_handle_escape(p, result[x]);
                        /* If i4l_handle_escape says NULL, say it now, doesn't matter
                        what else is there, the connection is dead. */
                        if (!f)
                            return NULL;
                    } else {
                        *(b++) = AST_MULAW((int)result[x]);
                        p->obuflen += 2;
                    }
                }
            }
            if (f)
                break;
        }
        if (f) {
            if( ! (!(p->dtmfmode & MODEM_DTMF_I4L) && f->frametype == AST_FRAME_DTMF))
                return f;
        }

        /* If we get here, we have a complete voice frame */
        p->fr.frametype = AST_FRAME_VOICE;
        p->fr.subclass = AST_FORMAT_SLINEAR;
        p->fr.samples = 240;
        p->fr.data = p->obuf;
        p->fr.datalen = p->obuflen;
        p->fr.mallocd = 0;
        p->fr.delivery.tv_sec = 0;
        p->fr.delivery.tv_usec = 0;
        p->fr.offset = AST_FRIENDLY_OFFSET;
        p->fr.src = __FUNCTION__;
        p->obuflen = 0;

        /* process with dsp */
        if (p->dsp) {
            f = ast_dsp_process(p->owner, p->dsp, &p->fr);
            if (f && (f->frametype == AST_FRAME_DTMF)) {
                ast_log(LOG_DEBUG, "Detected inband DTMF digit: %c on %s\n", f->subclass, p->dev);
                if (f->subclass == 'f') {
                    /* Fax tone -- Handle and return NULL */
                    struct ast_channel *ast = p->owner;
                    if (!p->faxhandled) {
                        p->faxhandled++;
                        if (strcmp(ast->exten, "fax")) {
                            const char *target_context = ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext;

                            if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
                                if (option_verbose > 2)
                                    ast_verbose(VERBOSE_PREFIX_3 "Redirecting %s to fax extension\n", ast->name);
                                /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
                                pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
                                if (ast_async_goto(ast, target_context, "fax", 1))
                                    ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
                            } else
                                ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
                        } else
                            ast_log(LOG_DEBUG, "Already in a fax extension, not redirecting\n");
                    } else
                        ast_log(LOG_DEBUG, "Fax already handled\n");
                    p->fr.frametype = AST_FRAME_NULL;
                    p->fr.subclass = 0;
                    f = &p->fr;
                }
                return f;
            }
        }

        return &p->fr;
    }
    return NULL;
}
static int macro_exec(struct ast_channel *chan, void *data)
{
	char *tmp;
	char *cur, *rest;
	char *macro;
	char fullmacro[80];
	char varname[80];
	char *oldargs[MAX_ARGS + 1] = { NULL, };
	int argc, x;
	int res=0;
	char oldexten[256]="";
	int oldpriority;
	char pc[80], depthc[12];
	char oldcontext[AST_MAX_CONTEXT] = "";
	char *offsets;
	int offset, depth;
	int setmacrocontext=0;
	int autoloopflag;
  
	char *save_macro_exten;
	char *save_macro_context;
	char *save_macro_priority;
	char *save_macro_offset;
	struct localuser *u;
 
	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Macro() requires arguments. See \"show application macro\" for help.\n");
		return -1;
	}

	LOCAL_USER_ADD(u);

	/* Count how many levels deep the rabbit hole goes */
	tmp = pbx_builtin_getvar_helper(chan, "MACRO_DEPTH");
	if (tmp) {
		sscanf(tmp, "%d", &depth);
	} else {
		depth = 0;
	}

	if (depth >= 7) {
		ast_log(LOG_ERROR, "Macro():  possible infinite loop detected.  Returning early.\n");
		LOCAL_USER_REMOVE(u);
		return 0;
	}
	snprintf(depthc, sizeof(depthc), "%d", depth + 1);
	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

	tmp = ast_strdupa(data);
	rest = tmp;
	macro = strsep(&rest, "|");
	if (ast_strlen_zero(macro)) {
		ast_log(LOG_WARNING, "Invalid macro name specified\n");
		LOCAL_USER_REMOVE(u);
		return 0;
	}
	snprintf(fullmacro, sizeof(fullmacro), "macro-%s", macro);
	if (!ast_exists_extension(chan, fullmacro, "s", 1, chan->cid.cid_num)) {
  		if (!ast_context_find(fullmacro)) 
			ast_log(LOG_WARNING, "No such context '%s' for macro '%s'\n", fullmacro, macro);
		else
	  		ast_log(LOG_WARNING, "Context '%s' for macro '%s' lacks 's' extension, priority 1\n", fullmacro, macro);
		LOCAL_USER_REMOVE(u);
		return 0;
	}
	
	/* Save old info */
	oldpriority = chan->priority;
	ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
	ast_copy_string(oldcontext, chan->context, sizeof(oldcontext));
	if (ast_strlen_zero(chan->macrocontext)) {
		ast_copy_string(chan->macrocontext, chan->context, sizeof(chan->macrocontext));
		ast_copy_string(chan->macroexten, chan->exten, sizeof(chan->macroexten));
		chan->macropriority = chan->priority;
		setmacrocontext=1;
	}
	argc = 1;
	/* Save old macro variables */
	save_macro_exten = pbx_builtin_getvar_helper(chan, "MACRO_EXTEN");
	if (save_macro_exten) 
		save_macro_exten = strdup(save_macro_exten);
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", oldexten);

	save_macro_context = pbx_builtin_getvar_helper(chan, "MACRO_CONTEXT");
	if (save_macro_context)
		save_macro_context = strdup(save_macro_context);
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", oldcontext);

	save_macro_priority = pbx_builtin_getvar_helper(chan, "MACRO_PRIORITY");
	if (save_macro_priority) 
		save_macro_priority = strdup(save_macro_priority);
	snprintf(pc, sizeof(pc), "%d", oldpriority);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", pc);
  
	save_macro_offset = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET");
	if (save_macro_offset) 
		save_macro_offset = strdup(save_macro_offset);
	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);

	/* Setup environment for new run */
	chan->exten[0] = 's';
	chan->exten[1] = '\0';
	ast_copy_string(chan->context, fullmacro, sizeof(chan->context));
	chan->priority = 1;

	while((cur = strsep(&rest, "|")) && (argc < MAX_ARGS)) {
  		/* Save copy of old arguments if we're overwriting some, otherwise
	   	let them pass through to the other macro */
  		snprintf(varname, sizeof(varname), "ARG%d", argc);
		oldargs[argc] = pbx_builtin_getvar_helper(chan, varname);
		if (oldargs[argc])
			oldargs[argc] = strdup(oldargs[argc]);
		pbx_builtin_setvar_helper(chan, varname, cur);
		argc++;
	}
	autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
	ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
	while(ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num)) {
		/* Reset the macro depth, if it was changed in the last iteration */
		pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
		if ((res = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num))) {
			/* Something bad happened, or a hangup has been requested. */
			if (((res >= '0') && (res <= '9')) || ((res >= 'A') && (res <= 'F')) ||
		    	(res == '*') || (res == '#')) {
				/* Just return result as to the previous application as if it had been dialed */
				ast_log(LOG_DEBUG, "Oooh, got something to jump out with ('%c')!\n", res);
				break;
			}
			switch(res) {
	        	case MACRO_EXIT_RESULT:
                        	res = 0;
				goto out;
			case AST_PBX_KEEPALIVE:
				if (option_debug)
					ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited KEEPALIVE in macro %s on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
				else if (option_verbose > 1)
					ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited KEEPALIVE in macro '%s' on '%s'\n", chan->context, chan->exten, chan->priority, macro, chan->name);
				goto out;
				break;
			default:
				if (option_debug)
					ast_log(LOG_DEBUG, "Spawn extension (%s,%s,%d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
				else if (option_verbose > 1)
					ast_verbose( VERBOSE_PREFIX_2 "Spawn extension (%s, %s, %d) exited non-zero on '%s' in macro '%s'\n", chan->context, chan->exten, chan->priority, chan->name, macro);
				goto out;
			}
		}
		if (strcasecmp(chan->context, fullmacro)) {
			if (option_verbose > 1)
				ast_verbose(VERBOSE_PREFIX_2 "Channel '%s' jumping out of macro '%s'\n", chan->name, macro);
			break;
		}
		/* don't stop executing extensions when we're in "h" */
		if (chan->_softhangup && strcasecmp(oldexten,"h")) {
			ast_log(LOG_DEBUG, "Extension %s, priority %d returned normally even though call was hung up\n",
				chan->exten, chan->priority);
			goto out;
		}
		chan->priority++;
  	}
	out:
	/* Reset the depth back to what it was when the routine was entered (like if we called Macro recursively) */
	snprintf(depthc, sizeof(depthc), "%d", depth);
	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);

	ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
  	for (x=1; x<argc; x++) {
  		/* Restore old arguments and delete ours */
		snprintf(varname, sizeof(varname), "ARG%d", x);
  		if (oldargs[x]) {
			pbx_builtin_setvar_helper(chan, varname, oldargs[x]);
			free(oldargs[x]);
		} else {
			pbx_builtin_setvar_helper(chan, varname, NULL);
		}
  	}

	/* Restore macro variables */
	pbx_builtin_setvar_helper(chan, "MACRO_EXTEN", save_macro_exten);
	if (save_macro_exten)
		free(save_macro_exten);
	pbx_builtin_setvar_helper(chan, "MACRO_CONTEXT", save_macro_context);
	if (save_macro_context)
		free(save_macro_context);
	pbx_builtin_setvar_helper(chan, "MACRO_PRIORITY", save_macro_priority);
	if (save_macro_priority)
		free(save_macro_priority);
	if (setmacrocontext) {
		chan->macrocontext[0] = '\0';
		chan->macroexten[0] = '\0';
		chan->macropriority = 0;
	}

	if (!strcasecmp(chan->context, fullmacro)) {
  		/* If we're leaving the macro normally, restore original information */
		chan->priority = oldpriority;
		ast_copy_string(chan->context, oldcontext, sizeof(chan->context));
		if (!(chan->_softhangup & AST_SOFTHANGUP_ASYNCGOTO)) {
			/* Copy the extension, so long as we're not in softhangup, where we could be given an asyncgoto */
			ast_copy_string(chan->exten, oldexten, sizeof(chan->exten));
			if ((offsets = pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"))) {
				/* Handle macro offset if it's set by checking the availability of step n + offset + 1, otherwise continue
			   	normally if there is any problem */
				if (sscanf(offsets, "%d", &offset) == 1) {
					if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + offset + 1, chan->cid.cid_num)) {
						chan->priority += offset;
					}
				}
			}
		}
	}

	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", save_macro_offset);
	if (save_macro_offset)
		free(save_macro_offset);
	LOCAL_USER_REMOVE(u);
	return res;
}
Example #16
0
static int nv_detectfax_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	char tmp[256] = "\0";
	char *p = NULL;
	char *waitstr = NULL;
	char *options = NULL;
	char *silstr = NULL;
	char *minstr = NULL;
	char *maxstr = NULL;
	struct ast_frame *fr = NULL;
	struct ast_frame *fr2 = NULL;
	int notsilent = 0;
	struct timeval start = {0, 0}, end = {0, 0};
	int waitdur = 4;
	int sildur = 1000;
	int mindur = 100;
	int maxdur = -1;
	int skipanswer = 0;
	int noextneeded = 0;
	int ignoredtmf = 0;
	int ignorefax = 0;
	int ignoretalk = 0;
	int x = 0;
	struct ast_format* origrformat = NULL;
	int features = 0;
	time_t timeout = 0;
	struct ast_dsp *dsp = NULL;
	
	struct ast_format_cap *cap;
	struct ast_format linearFormat;
	
	/* linear format capabilities */
	ast_format_set(&linearFormat, AST_FORMAT_SLINEAR, 0);
	cap = ast_format_cap_alloc_nolock();
	ast_format_cap_add(cap, &linearFormat);
	/* done */
	
	pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "FAXEXTEN", "");
	pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "");
	pbx_builtin_setvar_helper(chan, "TALK_DETECTED", "");
	
	if (data || !ast_strlen_zero(data)) {
		strncpy(tmp, data, sizeof(tmp)-1);
	}	
	
	p = tmp;
	
	waitstr = strsep(&p, ",");
	options = strsep(&p, ",");
	silstr = strsep(&p, ",");
	minstr = strsep(&p, ",");	
	maxstr = strsep(&p, ",");	
	
	if (waitstr) {
		if ((sscanf(waitstr, "%d", &x) == 1) && (x > 0))
			waitdur = x;
	}
	
	if (options) {
		if (strchr(options, 'n'))
			skipanswer = 1;
		if (strchr(options, 'x'))
			noextneeded = 1;
		if (strchr(options, 'd'))
			ignoredtmf = 1;
		if (strchr(options, 'f'))
			ignorefax = 1;
		if (strchr(options, 't'))
			ignoretalk = 1;
	}
	
	if (silstr) {
		if ((sscanf(silstr, "%d", &x) == 1) && (x > 0))
			sildur = x;
	}
	
	if (minstr) {
		if ((sscanf(minstr, "%d", &x) == 1) && (x > 0))
			mindur = x;
	}
	
	if (maxstr) {
		if ((sscanf(maxstr, "%d", &x) == 1) && (x > 0))
			maxdur = x;
	}
	
	ast_log(LOG_DEBUG, "Preparing detect of fax (waitdur=%dms, sildur=%dms, mindur=%dms, maxdur=%dms)\n", 
						waitdur, sildur, mindur, maxdur);
						
	//	LOCAL_USER_ADD(u);
// 	if (chan->_state != AST_STATE_UP && !skipanswer) {
	if (ast_channel_state(chan) != AST_STATE_UP && !skipanswer) {
		/* Otherwise answer unless we're supposed to send this while on-hook */
		res = ast_answer(chan);
	}
	if (!res) {
// 		origrformat = chan->readformat;
		origrformat = ast_channel_readformat(chan);
		
// 		if ((res = ast_set_read_format(chan, AST_FORMAT_SLINEAR))) 
		if ((res = ast_set_read_format_from_cap(chan, cap)) ){
			ast_log(LOG_WARNING, "Unable to set read format to linear!\n");
		}
	}
	if (!(dsp = ast_dsp_new())) {
		ast_log(LOG_WARNING, "Unable to allocate DSP!\n");
		res = -1;
	}
	
	if (dsp) {	
		if (!ignoretalk)
			; /* features |= DSP_FEATURE_SILENCE_SUPPRESS; */
		if (!ignorefax)
			features |= DSP_FEATURE_FAX_DETECT;
		//if (!ignoredtmf)
			features |= DSP_FEATURE_DIGIT_DETECT;
			
		ast_dsp_set_threshold(dsp, 256); 
		ast_dsp_set_features(dsp, features | DSP_DIGITMODE_RELAXDTMF);
		ast_dsp_set_digitmode(dsp, DSP_DIGITMODE_DTMF);
	}

	if (!res) {
		if (waitdur > 0)
			timeout = time(NULL) + (time_t)waitdur;

		while(ast_waitfor(chan, -1) > -1) {
			if (waitdur > 0 && time(NULL) > timeout) {
				res = 0;
				break;
			}

			fr = ast_read(chan);
			if (!fr) {
				ast_log(LOG_DEBUG, "Got hangup\n");
				res = -1;
				break;
			}

			fr2 = ast_dsp_process(chan, dsp, fr);
			if (!fr2) {
				ast_log(LOG_WARNING, "Bad DSP received (what happened?)\n");
				fr2 = fr;
			} 

			if (fr2->frametype == AST_FRAME_DTMF) {
				if (fr2->subclass.integer == 'f' && !ignorefax) {
					/* Fax tone -- Handle and return NULL */
					ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan));
					ast_log(LOG_DEBUG, "Fax detected on %s\n", ast_channel_name(chan));
					if (strcmp(ast_channel_exten(chan), "fax")) {
						ast_log(LOG_NOTICE, "Redirecting %s to fax extension\n", ast_channel_name(chan));
						pbx_builtin_setvar_helper(chan, "FAX_DETECTED", "1");
						pbx_builtin_setvar_helper(chan,"FAXEXTEN",ast_channel_exten(chan));								
						if (ast_exists_extension(chan, ast_channel_context(chan), "fax", 1, ast_channel_caller(chan)->id.number.str)) {
							/* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
// 							strncpy(ast_channel_exten(chan), "fax", sizeof(ast_channel_exten(chan))-1);
// 							chan->priority = 0;
							ast_channel_exten_set(chan, "fax");
							ast_channel_priority_set(chan, 0);
						} else
							ast_log(LOG_WARNING, "Fax detected, but no fax extension\n");
					} else
						ast_log(LOG_WARNING, "Already in a fax extension, not redirecting\n");

					res = 0;
					ast_frfree(fr);
					break;
				} else if (!ignoredtmf) {
					ast_log(LOG_DEBUG, "DTMF detected on %s\n", ast_channel_name(chan));
					char t[2];
					t[0] = fr2->subclass.integer;
					t[1] = '\0';
					if (noextneeded || ast_canmatch_extension(chan, ast_channel_context(chan), t, 1, ast_channel_caller(chan)->id.number.str)) {
						pbx_builtin_setvar_helper(chan, "DTMF_DETECTED", "1");
						/* They entered a valid extension, or might be anyhow */
						if (noextneeded) {
							ast_log(LOG_NOTICE, "DTMF received (not matching to exten)\n");
							res = 0;
						} else {
							ast_log(LOG_NOTICE, "DTMF received (matching to exten)\n");
							res = fr2->subclass.integer;
						}
						ast_frfree(fr);
						break;
					} else
						ast_log(LOG_DEBUG, "Valid extension requested and DTMF did not match\n");
				}
// 			} else if ((fr->frametype == AST_FRAME_VOICE) && (fr->subclass == AST_FORMAT_SLINEAR) && !ignoretalk) {
			} else if ((fr->frametype == AST_FRAME_VOICE) && ( ast_format_cap_iscompatible(cap, &fr->subclass.format)) && !ignoretalk) {
				int totalsilence;
				int ms;
				res = ast_dsp_silence(dsp, fr, &totalsilence);
				if (res && (totalsilence > sildur)) {
					/* We've been quiet a little while */
					if (notsilent) {
						/* We had heard some talking */
						gettimeofday(&end, NULL);
						ms = (end.tv_sec - start.tv_sec) * 1000;
						ms += (end.tv_usec - start.tv_usec) / 1000;
						ms -= sildur;
						if (ms < 0)
							ms = 0;
						if ((ms > mindur) && ((maxdur < 0) || (ms < maxdur))) {
							char ms_str[10];
							ast_log(LOG_DEBUG, "Found qualified token of %d ms\n", ms);
							ast_log(LOG_NOTICE, "Redirecting %s to talk extension\n", ast_channel_name(chan));

							/* Save detected talk time (in milliseconds) */ 
							sprintf(ms_str, "%d", ms);	
							pbx_builtin_setvar_helper(chan, "TALK_DETECTED", ms_str);

							if (ast_exists_extension(chan, ast_channel_context(chan), "talk", 1, ast_channel_caller(chan)->id.number.str)) {
// 								strncpy(ast_channel_exten(chan), "talk", sizeof(ast_channel_exten(chan)) - 1);
// 								chan->priority = 0;
								ast_channel_exten_set(chan, "talk");
								ast_channel_priority_set(chan, 0);
							} else
								ast_log(LOG_WARNING, "Talk detected, but no talk extension\n");
							res = 0;
							ast_frfree(fr);
							break;
						} else
							ast_log(LOG_DEBUG, "Found unqualified token of %d ms\n", ms);
						notsilent = 0;
					}
				} else {
					if (!notsilent) {
						/* Heard some audio, mark the begining of the token */
						gettimeofday(&start, NULL);
						ast_log(LOG_DEBUG, "Start of voice token!\n");
						notsilent = 1;
					}
				}						
			}
			ast_frfree(fr);
		}
	} else
		ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(chan));
	
	if (res > -1) {
		if (origrformat && ast_set_read_format(chan, origrformat)) {
			ast_log(LOG_WARNING, "Failed to restore read format for %s to %s\n", 
				ast_channel_name(chan), ast_getformatname(origrformat));
		}
	}
	
	if (dsp)
		ast_dsp_free(dsp);
	
	//	LOCAL_USER_REMOVE(u);
	ast_format_cap_destroy(cap);
	return res;
}
Example #17
0
static int app_exec(struct ast_channel *chan, void *data)
{
	int res = 0, argc = 0, max_digits = 0, timeout = 0, alreadyran = 0, old_writeformat = 0;
	int ms, len, availatend;
	char *argv[3], *parse = NULL, *text = NULL, *rc = NULL;
	char tmp_exten[2], results[20];
	struct ast_module_user *u;
	struct ast_frame *f;
	struct timeval next;
	struct stuff *ps;

	struct myframe {
		struct ast_frame f;
		unsigned char offset[AST_FRIENDLY_OFFSET];
		unsigned char frdata[framesize];
	} myf;

	swift_engine *engine;
	swift_port *port = NULL;
	swift_voice *voice;
	swift_params *params;
	swift_result_t sresult;
	swift_background_t tts_stream;
	unsigned int event_mask;

	memset(results, 0 ,20);
	memset(tmp_exten, 0, 2);
	memset(argv, 0, 3);

	parse = ast_strdupa(data);
	u = ast_module_user_add(chan);
	argc = ast_app_separate_args(parse, ',', argv, 3);
	text = argv[0];

	if (!ast_strlen_zero(argv[1])) {
		timeout = strtol(argv[1], NULL, 0);
	}
	if (!ast_strlen_zero(argv[2])) {
		max_digits = strtol(argv[2], NULL, 0);
	}
	if (ast_strlen_zero(text)) {
		ast_log(LOG_WARNING, "%s requires text to speak!\n", app);
		return -1;
	}
	if (!ast_strlen_zero(text)) {
		ast_log(LOG_DEBUG, "Text to Speak : %s\n", text);
	}
	if (timeout > 0) {
		ast_log(LOG_DEBUG, "Timeout : %d\n", timeout);
	}
	if (max_digits > 0) {
		ast_log(LOG_DEBUG, "Max Digits : %d\n", max_digits);
	}

	ps = malloc(sizeof(struct stuff));
	swift_init_stuff(ps);

	/* Setup synthesis */

	if ((engine = swift_engine_open(NULL)) == NULL) {
		ast_log(LOG_ERROR, "Failed to open Swift Engine.\n");
		goto exception;
	}

	params = swift_params_new(NULL);
	swift_params_set_string(params, "audio/encoding", "ulaw");
	swift_params_set_string(params, "audio/sampling-rate", "8000");
	swift_params_set_string(params, "audio/output-format", "raw");
	swift_params_set_string(params, "tts/text-encoding", "utf-8");

	/* Additional swift parameters
	 *
	 * swift_params_set_float(params, "speech/pitch/shift", 1.0);
	 * swift_params_set_int(params, "speech/rate", 150);
	 * swift_params_set_int(params, "audio/volume", 110);
	 * swift_params_set_int(params, "audio/deadair", 0);
	 */

	if ((port = swift_port_open(engine, params)) == NULL) {
		ast_log(LOG_ERROR, "Failed to open Swift Port.\n");
		goto exception;
	}
	if ((voice = swift_port_set_voice_by_name(port, cfg_voice)) == NULL) {
		ast_log(LOG_ERROR, "Failed to set voice.\n");
		goto exception;
	}

	event_mask = SWIFT_EVENT_AUDIO | SWIFT_EVENT_END;
	swift_port_set_callback(port, &swift_cb, event_mask, ps);

	if (SWIFT_FAILED(swift_port_speak_text(port, text, 0, NULL, &tts_stream, NULL))) {
		ast_log(LOG_ERROR, "Failed to speak.\n");
		goto exception;
	}
	if (chan->_state != AST_STATE_UP) {
		ast_answer(chan);
	}

	ast_stopstream(chan);
	old_writeformat = chan->writeformat;

	if (ast_set_write_format(chan, AST_FORMAT_ULAW) < 0) {
		ast_log(LOG_WARNING, "Unable to set write format.\n");
		goto exception;
	}

	res = 0;

	/* Wait 100ms first for synthesis to start crankin'; if that's not
	 * enough the
	 */

	next = ast_tvadd(ast_tvnow(), ast_tv(0, 100000));

	while (swift_generator_running(ps)) {
		ms = ast_tvdiff_ms(next, ast_tvnow());

		if (ms <= 0) {
			if (swift_bytes_available(ps) > 0) {
				ASTOBJ_WRLOCK(ps);
				len = fmin(framesize, ps->qc);
				availatend = cfg_buffer_size - (ps->pq_r - ps->q);

				if (len > availatend) {
					/* read #1: to end of q buf */
					memcpy(myf.frdata, ps->pq_r, availatend);
					ps->qc -= availatend;

					/* read #2: reset to start of q buf and get rest */
					ps->pq_r = ps->q;
					memcpy(myf.frdata + availatend, ps->pq_r, len - availatend);
					ps->qc -= len - availatend;
					ps->pq_r += len - availatend;
				} else {
					ast_log(LOG_DEBUG, "Easy read; %d bytes and %d at end, %d free\n", len, availatend, cfg_buffer_size - ps->qc);
					memcpy(myf.frdata, ps->pq_r, len);
					ps->qc -= len;
					ps->pq_r += len;
				}

				myf.f.frametype = AST_FRAME_VOICE;
				myf.f.subclass = AST_FORMAT_ULAW;
				myf.f.datalen = len;
				myf.f.samples = len;
				myf.f.data.ptr = myf.frdata;
				myf.f.mallocd = 0;
				myf.f.offset = AST_FRIENDLY_OFFSET;
				myf.f.src = __PRETTY_FUNCTION__;
				myf.f.delivery.tv_sec = 0;
				myf.f.delivery.tv_usec = 0;

				if (ast_write(chan, &myf.f) < 0) {
					ast_log(LOG_DEBUG, "ast_write failed\n");
				}

				ast_log(LOG_DEBUG, "wrote a frame of %d\n", len);

				if (ps->qc < 0) {
					ast_log(LOG_DEBUG, "queue claims to contain negative bytes. Huh? qc < 0\n");
				}

				ASTOBJ_UNLOCK(ps);
				next = ast_tvadd(next, ast_samp2tv(myf.f.samples, samplerate));
			} else {
				next = ast_tvadd(next, ast_samp2tv(framesize / 2, samplerate));
				ast_log(LOG_DEBUG, "Whoops, writer starved for audio\n");
			}
		} else {
			ms = ast_waitfor(chan, ms);

			if (ms < 0) {
				ast_log(LOG_DEBUG, "Hangup detected\n");
				res = -1;
				ASTOBJ_WRLOCK(ps);
				ps->immediate_exit = 1;
				ASTOBJ_UNLOCK(ps);
			} else if (ms) {
				f = ast_read(chan);

				if (!f) {
					ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
					res = -1;
					ASTOBJ_WRLOCK(ps);
					ps->immediate_exit = 1;
					ASTOBJ_UNLOCK(ps);
				} else if (f->frametype == AST_FRAME_DTMF && timeout > 0 && max_digits > 0) {
					char originDTMF = f->subclass;
					alreadyran = 1;
					res = 0;
					ASTOBJ_WRLOCK(ps);
					ps->immediate_exit = 1;
					ASTOBJ_UNLOCK(ps);

					if (max_digits > 1) {
						rc = listen_for_dtmf(chan, timeout, max_digits - 1);
					}
					if (rc) {
						sprintf(results, "%c%s", originDTMF, rc);
					} else {
						sprintf(results, "%c", originDTMF);
					}

					ast_log(LOG_NOTICE, "DTMF = %s\n", results);
					pbx_builtin_setvar_helper(chan, "SWIFT_DTMF", results);
				}
				ast_frfree(f);
			}
		}

		ASTOBJ_RDLOCK(ps);

		if (ps->immediate_exit && !ps->generating_done) {
			if (SWIFT_FAILED(sresult = swift_port_stop(port, tts_stream, SWIFT_EVENT_NOW))) {
				ast_log(LOG_NOTICE, "Early top of swift port failed\n");
			}
		}

		ASTOBJ_UNLOCK(ps);
	}
	if (alreadyran == 0 && timeout > 0 && max_digits > 0) {
		rc = listen_for_dtmf(chan, timeout, max_digits);

		if (rc != NULL) {
			sprintf(results, "%s", rc);
			ast_log(LOG_NOTICE, "DTMF = %s\n", results);
			pbx_builtin_setvar_helper(chan, "SWIFT_DTMF", results);
		}
	}
	if (max_digits >= 1 && results != NULL) {
		if (cfg_goto_exten) {
			ast_log(LOG_NOTICE, "GoTo(%s|%s|%d) : ", chan->context, results, 1);

			if (ast_exists_extension (chan, chan->context, results, 1, chan->cid.cid_num)) {
				ast_log(LOG_NOTICE, "OK\n");
				ast_copy_string(chan->exten, results, sizeof(chan->exten) - 1);
				chan->priority = 0;
			} else {
				ast_log(LOG_NOTICE, "FAILED\n");
			}
		}
	}

	exception:

	if (port != NULL) {
		swift_port_close(port);
	}
	if (engine != NULL) {
		swift_engine_close(engine);
	}
	if (ps && ps->q) {
		ast_free(ps->q);
		ps->q = NULL;
	}
	if (ps) {
		ast_free(ps);
		ps = NULL;
	}
	if (!res && old_writeformat) {
		ast_set_write_format(chan, old_writeformat);
	}

	ast_module_user_remove(u);
	return res;
}