예제 #1
0
static struct ast_channel *media_request_helper(struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids,
	const struct ast_channel *requestor, const char *data, struct ast_channel_tech *tech, const char *role)
{
	struct ast_channel *chan;
	ast_callid callid;

	RAII_VAR(struct ast_unreal_pvt *, pvt, NULL, ao2_cleanup);

	if (!(pvt = ast_unreal_alloc(sizeof(*pvt), ast_unreal_destructor, cap))) {
		return NULL;
	}

	ast_copy_string(pvt->name, data, sizeof(pvt->name));

	ast_set_flag(pvt, AST_UNREAL_NO_OPTIMIZATION);

	callid = ast_read_threadstorage_callid();

	chan = ast_unreal_new_channels(pvt, tech,
		AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, callid);
	if (!chan) {
		return NULL;
	}

	ast_answer(pvt->owner);
	ast_answer(pvt->chan);

	if (ast_channel_add_bridge_role(pvt->chan, role)) {
		ast_hangup(chan);
		return NULL;
	}

	return chan;
}
예제 #2
0
static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
{
	struct ast_channel *chan;
	const char *conf_name = data;

	/* Allocate a new private structure and then Asterisk channels */
	struct announce_pvt *pvt = (struct announce_pvt *) ast_unreal_alloc(sizeof(*pvt), announce_pvt_destructor, cap);
	if (!pvt) {
		return NULL;
	}
	ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
	ast_copy_string(pvt->base.name, conf_name, sizeof(pvt->base.name));

#if !defined(CS_AST_CHANNEL_CALLID_TYPEDEF)
	chan = ast_unreal_new_channels(&pvt->base, sccpconf_announce_get_tech(), AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, NULL);
#else
	chan = ast_unreal_new_channels(&pvt->base, sccpconf_announce_get_tech(), AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, 0);
#endif
	if (chan) {
		ast_answer(pvt->base.owner);
		ast_answer(pvt->base.chan);
		if (ast_channel_add_bridge_role(pvt->base.chan, "announcer")) {
			ast_hangup(chan);
			chan = NULL;
		}
	}
	ao2_cleanup(pvt);

	return chan;
}
예제 #3
0
static int waitforsilence_exec(struct ast_channel *chan, void *data)
{
	int res = 1;
	int silencereqd = 1000;
	int timeout = 0;
	int iterations = 1, i;
	time_t waitstart;

	res = ast_answer(chan); /* Answer the channel */

	if (!data || ( (sscanf(data, "%d|%d|%d", &silencereqd, &iterations, &timeout) != 3) &&
		(sscanf(data, "%d|%d", &silencereqd, &iterations) != 2) &&
		(sscanf(data, "%d", &silencereqd) != 1) ) ) {
		ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration, no timeout\n");
	}

	if (option_verbose > 2)
		ast_verbose(VERBOSE_PREFIX_3 "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, silencereqd, timeout);

	time(&waitstart);
	res = 1;
	for (i=0; (i<iterations) && (res == 1); i++) {
		res = do_waiting(chan, silencereqd, waitstart, timeout);
	}
	if (res > 0)
		res = 0;
	return res;
}
예제 #4
0
/*--- count_exec: The MeetmeCount application */
static int count_exec(struct ast_channel *chan, void *data)
{
	struct localuser *u;
	int res = 0;
	struct ast_conference *conf;
	int count;
	char *confnum, *localdata;
	char val[80] = "0"; 

	if (!data || ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "MeetMeCount requires an argument (conference number)\n");
		return -1;
	}
	localdata = ast_strdupa(data);
	LOCAL_USER_ADD(u);
	confnum = strsep(&localdata,"|");       
	conf = find_conf(chan, confnum, 0, 0, NULL);
	if (conf)
		count = conf->users;
	else
		count = 0;

	if (localdata && !ast_strlen_zero(localdata)){
		/* have var so load it and exit */
		snprintf(val,sizeof(val), "%i",count);
		pbx_builtin_setvar_helper(chan, localdata,val);
	} else {
		if (chan->_state != AST_STATE_UP)
			ast_answer(chan);
		res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */
	}
	LOCAL_USER_REMOVE(u);
	return res;
}
예제 #5
0
static int dahdiras_exec(struct ast_channel *chan, const char *data)
{
    int res=-1;
    char *args;
    struct dahdi_params dahdip;

    if (!data)
        data = "";

    args = ast_strdupa(data);

    /* Answer the channel if it's not up */
    if (ast_channel_state(chan) != AST_STATE_UP)
        ast_answer(chan);
    if (strcasecmp(ast_channel_tech(chan)->type, "DAHDI")) {
        /* If it's not a DAHDI channel, we're done.  Wait a couple of
           seconds and then hangup... */
        ast_verb(2, "Channel %s is not a DAHDI channel\n", ast_channel_name(chan));
        sleep(2);
    } else {
        memset(&dahdip, 0, sizeof(dahdip));
        if (ioctl(ast_channel_fd(chan, 0), DAHDI_GET_PARAMS, &dahdip)) {
            ast_log(LOG_WARNING, "Unable to get DAHDI parameters\n");
        } else if (dahdip.sigtype != DAHDI_SIG_CLEAR) {
            ast_verb(2, "Channel %s is not a clear channel\n", ast_channel_name(chan));
        } else {
            /* Everything should be okay.  Run PPP. */
            ast_verb(3, "Starting RAS on %s\n", ast_channel_name(chan));
            /* Execute RAS */
            run_ras(chan, args);
        }
    }
    return res;
}
예제 #6
0
static int steal_channel(struct ast_channel *chan, void *pattern)
{
	int ret = 0;
	struct ast_module_user *u;
	struct ast_channel *cur;
	u = ast_module_user_add(chan);
	cur = find_matching_channel(chan, pattern, AST_STATE_UP);
	if (cur) {
		ast_verbose(VERBOSE_PREFIX_3 
			"Channel %s stole channel %s\n",
			chan->name, cur->name);
		pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", cur->name);
		if (chan->_state != AST_STATE_UP) {
			ast_answer(chan);
		}
		if (cur->_bridge) {
			if (!ast_mutex_lock(&cur->_bridge->lock)) {
				ast_moh_stop(cur->_bridge);
				ast_mutex_unlock(&cur->_bridge->lock);
			}
		}
			
		if (ast_channel_masquerade(cur, chan)) {
			ast_log(LOG_ERROR, "unable to masquerade\n");
			ret = -1;
		}
		ast_mutex_unlock(&cur->lock);
		ast_mutex_unlock(&chan->lock);
	} else {
		pbx_builtin_setvar_helper(chan, "STEAL_CHANNEL", "");
	}
	ast_module_user_remove(u);
	return(ret);
}
static int waitforsilence_exec(struct ast_channel *chan, void *data)
{
	int res = 1;
	struct localuser *u;
	int maxsilence = 1000;
	int iterations = 1, i;

	LOCAL_USER_ADD(u);
	
	res = ast_answer(chan); /* Answer the channel */

	if (!data || ((sscanf(data, "%d|%d", &maxsilence, &iterations) != 2) &&
		(sscanf(data, "%d", &maxsilence) != 1))) {
		ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration\n");
	}

	if (option_verbose > 2)
		ast_verbose(VERBOSE_PREFIX_3 "Waiting %d time(s) for %d ms silence\n", iterations, maxsilence);
	
	res = 1;
	for (i=0; (i<iterations) && (res == 1); i++) {
		res = do_waiting(chan, maxsilence);
	}
	LOCAL_USER_REMOVE(u);
	if (res > 0)
		res = 0;
	return res;
}
예제 #8
0
/*! \brief Called when we want to place a call somewhere, but not actually call it... yet */
static struct ast_channel *bridge_request(const char *type, struct ast_format_cap *cap, const struct ast_channel *requestor, void *data, int *cause)
{
	struct bridge_pvt *p = NULL;
	struct ast_format slin;

	/* Try to allocate memory for our very minimal pvt structure */
	if (!(p = ao2_alloc(sizeof(*p), NULL))) {
		return NULL;
	}

	/* Try to grab two Asterisk channels to use as input and output channels */
	if (!(p->input = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-input", p))) {
		ao2_ref(p, -1);
		return NULL;
	}
	if (!(p->output = ast_channel_alloc(1, AST_STATE_UP, 0, 0, "", "", "", requestor ? requestor->linkedid : NULL, 0, "Bridge/%p-output", p))) {
		p->input = ast_channel_release(p->input);
		ao2_ref(p, -1);
		return NULL;
	}

	/* Setup parameters on both new channels */
	p->input->tech = p->output->tech = &bridge_tech;

	ao2_ref(p, 2);
	p->input->tech_pvt = p->output->tech_pvt = p;

	ast_format_set(&slin, AST_FORMAT_SLINEAR, 0);

	ast_format_cap_add(p->input->nativeformats, &slin);
	ast_format_cap_add(p->output->nativeformats, &slin);
	ast_format_copy(&p->input->readformat, &slin);
	ast_format_copy(&p->output->readformat, &slin);
	ast_format_copy(&p->input->rawreadformat, &slin);
	ast_format_copy(&p->output->rawreadformat, &slin);
	ast_format_copy(&p->input->writeformat, &slin);
	ast_format_copy(&p->output->writeformat, &slin);
	ast_format_copy(&p->input->rawwriteformat, &slin);
	ast_format_copy(&p->output->rawwriteformat, &slin);

	ast_answer(p->output);
	ast_answer(p->input);

	/* remove the reference from the alloc. The channels now own the pvt. */
	ao2_ref(p, -1);
	return p->input;
}
예제 #9
0
static int transmit(fax_session *s)
{
	int res = 0;

	/* Clear all channel variables which to be set by the application.
	   Pre-set status to error so in case of any problems we can just leave */
	pbx_builtin_setvar_helper(s->chan, "FAXSTATUS", "FAILED"); 
	pbx_builtin_setvar_helper(s->chan, "FAXERROR", "Channel problems"); 

	pbx_builtin_setvar_helper(s->chan, "FAXMODE", NULL);
	pbx_builtin_setvar_helper(s->chan, "REMOTESTATIONID", NULL);
	pbx_builtin_setvar_helper(s->chan, "FAXPAGES", "0");
	pbx_builtin_setvar_helper(s->chan, "FAXRESOLUTION", NULL);
	pbx_builtin_setvar_helper(s->chan, "FAXBITRATE", NULL); 

	if (ast_channel_state(s->chan) != AST_STATE_UP) {
		/* Shouldn't need this, but checking to see if channel is already answered
		 * Theoretically asterisk should already have answered before running the app */
		res = ast_answer(s->chan);
		if (res) {
			ast_log(LOG_WARNING, "Could not answer channel '%s'\n", ast_channel_name(s->chan));
			return res;
		}
	}

	s->t38state = ast_channel_get_t38_state(s->chan);
	if (s->t38state != T38_STATE_NEGOTIATED) {
		/* T38 is not negotiated on the channel yet. First start regular transmission. If it switches to T38, follow */	
		pbx_builtin_setvar_helper(s->chan, "FAXMODE", "audio"); 
		res = transmit_audio(s);
		if (res > 0) {
			/* transmit_audio reports switchover to T38. Update t38state */
			s->t38state = ast_channel_get_t38_state(s->chan);
			if (s->t38state != T38_STATE_NEGOTIATED) {
				ast_log(LOG_ERROR, "Audio loop reports T38 switchover but t38state != T38_STATE_NEGOTIATED\n");
			}
		}
	}

	if (s->t38state == T38_STATE_NEGOTIATED) {
		pbx_builtin_setvar_helper(s->chan, "FAXMODE", "T38"); 
		res = transmit_t38(s);
	}

	if (res) {
		ast_log(LOG_WARNING, "Transmission error\n");
		res = -1;
	} else if (s->finished < 0) {
		ast_log(LOG_WARNING, "Transmission failed\n");
	} else if (s->finished > 0) {
		ast_debug(1, "Transmission finished Ok\n");
	}

	return res;
}
예제 #10
0
static int datetime_exec(struct ast_channel *chan, void *data)
{
	int res=0;
	time_t t;
	struct localuser *u;
	LOCAL_USER_ADD(u);
	time(&t);
	if (chan->_state != AST_STATE_UP)
		res = ast_answer(chan);
	if (!res)
		res = ast_say_datetime(chan, t, "", chan->language);
	LOCAL_USER_REMOVE(u);
	return res;
}
예제 #11
0
static int exec(struct ast_channel *chan, void *data, int dahdimode)
{
	int res=-1;
	struct ast_module_user *u;
	int retrycnt = 0;
	int confflags = 0;
	int confno = 0;
	char confstr[80] = "";

	u = ast_module_user_add(chan);
	
	if (!ast_strlen_zero(data)) {
		if (dahdimode) {
			if ((sscanf(data, "DAHDI/%30d", &confno) != 1) &&
			    (sscanf(data, "%30d", &confno) != 1)) {
				ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data);
				ast_module_user_remove(u);
				return 0;
			}
		} else {
			if ((sscanf(data, "Zap/%30d", &confno) != 1) &&
			    (sscanf(data, "%30d", &confno) != 1)) {
				ast_log(LOG_WARNING, "Argument (if specified) must be a channel number, not '%s'\n", (char *) data);
				ast_module_user_remove(u);
				return 0;
			}
		}
	}
	
	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	while(!confno && (++retrycnt < 4)) {
		/* Prompt user for conference number */
		confstr[0] = '\0';
		res = ast_app_getdata(chan, "conf-getchannel",confstr, sizeof(confstr) - 1, 0);
		if (res <0) goto out;
		if (sscanf(confstr, "%30d", &confno) != 1)
			confno = 0;
	}
	if (confno) {
		/* XXX Should prompt user for pin if pin is required XXX */
		/* Run the conference */
		res = conf_run(chan, confno, confflags);
	}
out:
	/* Do the conference */
	ast_module_user_remove(u);
	return res;
}
예제 #12
0
static struct ast_channel *announce_request(const char *type, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, const char *data, int *cause)
{
	struct ast_channel *chan;
	const char *conf_name = data;
	RAII_VAR(struct confbridge_conference *, conference, NULL, ao2_cleanup);
	RAII_VAR(struct announce_pvt *, pvt, NULL, ao2_cleanup);

	conference = ao2_find(conference_bridges, conf_name, OBJ_KEY);
	if (!conference) {
		return NULL;
	}
	ast_assert(conference->bridge != NULL);

	/* Allocate a new private structure and then Asterisk channels */
	pvt = (struct announce_pvt *) ast_unreal_alloc(sizeof(*pvt), announce_pvt_destructor,
		cap);
	if (!pvt) {
		return NULL;
	}
	ast_set_flag(&pvt->base, AST_UNREAL_NO_OPTIMIZATION);
	ast_copy_string(pvt->base.name, conf_name, sizeof(pvt->base.name));
	pvt->bridge = conference->bridge;
	ao2_ref(pvt->bridge, +1);

	chan = ast_unreal_new_channels(&pvt->base, conf_announce_get_tech(),
		AST_STATE_UP, AST_STATE_UP, NULL, NULL, assignedids, requestor, 0);
	if (chan) {
		ast_answer(pvt->base.owner);
		ast_answer(pvt->base.chan);
		if (ast_channel_add_bridge_role(pvt->base.chan, "announcer")) {
			ast_hangup(chan);
			chan = NULL;
		}
	}

	return chan;
}
예제 #13
0
static int bridgeadd_exec(struct ast_channel *chan, const char *data)
{
	struct ast_channel *c_ref;
	struct ast_bridge_features chan_features;
	struct ast_bridge *bridge;
	char *c_name;

	/* Answer the channel if needed */
	if (ast_channel_state(chan) != AST_STATE_UP) {
		ast_answer(chan);
	}

	if (!(c_ref = ast_channel_get_by_name_prefix(data, strlen(data)))) {
		ast_log(LOG_WARNING, "Channel %s not found\n", data);
		return -1;
	}

	c_name = ast_strdupa(ast_channel_name(c_ref));

	ast_channel_lock(c_ref);
	bridge = ast_channel_get_bridge(c_ref);
	ast_channel_unlock(c_ref);

	ast_channel_unref(c_ref);

	if (!bridge) {
		ast_log(LOG_WARNING, "Channel %s is not in a bridge\n", c_name);
		return -1;
	}

	ast_verb(3, "%s is joining %s in bridge %s\n", ast_channel_name(chan),
		c_name, bridge->uniqueid);

	if (ast_bridge_features_init(&chan_features)
		|| ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, 0)) {

		ast_log(LOG_WARNING, "%s failed to join %s in bridge %s\n", ast_channel_name(chan),
			 c_name, bridge->uniqueid);

		ast_bridge_features_cleanup(&chan_features);
		ao2_cleanup(bridge);
		return -1;
	}

	ast_bridge_features_cleanup(&chan_features);
	ao2_cleanup(bridge);
	return 0;
}
예제 #14
0
static int zapateller_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	struct localuser *u;
	int answer = 0, nocallerid = 0;
	char *c;
	char *stringp=NULL;
	
	LOCAL_USER_ADD(u);

	stringp=data;
        c = strsep(&stringp, "|");
        while(!ast_strlen_zero(c)) {
		if (!strcasecmp(c, "answer"))
			answer = 1;
		else if (!strcasecmp(c, "nocallerid"))
			nocallerid = 1;

                c = strsep(&stringp, "|");
        }

	ast_stopstream(chan);
	if (chan->_state != AST_STATE_UP) {

		if (answer) 
			res = ast_answer(chan);
		if (!res) {
			res = ast_safe_sleep(chan, 500);
		}
	}
	if (chan->cid.cid_num && nocallerid) {
		LOCAL_USER_REMOVE(u);
		return res;
	} 
	if (!res) 
		res = ast_tonepair(chan, 950, 0, 330, 0);
	if (!res) 
		res = ast_tonepair(chan, 1400, 0, 330, 0);
	if (!res) 
		res = ast_tonepair(chan, 1800, 0, 330, 0);
	if (!res) 
		res = ast_tonepair(chan, 0, 0, 1000, 0);
	LOCAL_USER_REMOVE(u);
	return res;
}
예제 #15
0
/*!
 * \brief Pickup a call
 * \param chan channel that initiated pickup.
 *
 * Walk list of channels, checking it is not itself, channel is pbx one,
 * check that the callgroup for both channels are the same and the channel is ringing.
 * Answer calling channel, flag channel as answered on queue, masq channels together.
 */
int ast_pickup_call(struct ast_channel *chan)
{
	struct ast_channel *target;/*!< Potential pickup target */
	int res = -1;
	RAII_VAR(struct ast_features_pickup_config *, pickup_cfg, NULL, ao2_cleanup);
	const char *pickup_sound;
	const char *fail_sound;

	ast_debug(1, "Pickup attempt by %s\n", ast_channel_name(chan));
	ast_channel_lock(chan);
	pickup_cfg = ast_get_chan_features_pickup_config(chan);
	if (!pickup_cfg) {
		ast_log(LOG_ERROR, "Unable to retrieve pickup configuration. Unable to play pickup sounds\n");
	}
	pickup_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupsound : "");
	fail_sound = ast_strdupa(pickup_cfg ? pickup_cfg->pickupfailsound : "");
	ast_channel_unlock(chan);

	/* The found channel is already locked. */
	target = ast_pickup_find_by_group(chan);
	if (target) {
		ast_log(LOG_NOTICE, "Pickup %s attempt by %s\n", ast_channel_name(target), ast_channel_name(chan));

		res = ast_do_pickup(chan, target);
		ast_channel_unlock(target);
		if (!res) {
			if (!ast_strlen_zero(pickup_sound)) {
				pbx_builtin_setvar_helper(target, "BRIDGE_PLAY_SOUND", pickup_sound);
			}
		} else {
			ast_log(LOG_WARNING, "Pickup %s failed by %s\n", ast_channel_name(target), ast_channel_name(chan));
		}
		target = ast_channel_unref(target);
	}

	if (res < 0) {
		ast_debug(1, "No call pickup possible... for %s\n", ast_channel_name(chan));
		if (!ast_strlen_zero(fail_sound)) {
			ast_answer(chan);
			ast_stream_and_wait(chan, fail_sound, "");
		}
	}

	return res;
}
예제 #16
0
static int skel_exec(struct ast_channel *chan, const char *data)
{
	int res=0;
	char *tmp;

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
		return -1;
	}

	tmp = ast_strdupa(data);

	/* Do our thing here */

	if (ast_channel_state(chan) != AST_STATE_UP)
		res = ast_answer(chan);
	if (!res)
		res = ast_ivr_menu_run(chan, &ivr_demo, tmp);

	return res;
}
예제 #17
0
static int milliwatt_exec(struct ast_channel *chan, void *data)
{

	struct localuser *u;
	LOCAL_USER_ADD(u);
	ast_set_write_format(chan, AST_FORMAT_ULAW);
	ast_set_read_format(chan, AST_FORMAT_ULAW);
	if (chan->_state != AST_STATE_UP)
	{
		ast_answer(chan);
	}
	if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0)
	{
		ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",chan->name);
		return -1;
	}
	while(!ast_safe_sleep(chan, 10000));
	ast_deactivate_generator(chan);
	LOCAL_USER_REMOVE(u);
	return -1;
}
예제 #18
0
static int old_milliwatt_exec(struct ast_channel *chan)
{
	ast_set_write_format_by_id(chan, AST_FORMAT_ULAW);
	ast_set_read_format_by_id(chan, AST_FORMAT_ULAW);

	if (ast_channel_state(chan) != AST_STATE_UP) {
		ast_answer(chan);
	}

	if (ast_activate_generator(chan,&milliwattgen,"milliwatt") < 0) {
		ast_log(LOG_WARNING,"Failed to activate generator on '%s'\n",ast_channel_name(chan));
		return -1;
	}

	while (!ast_safe_sleep(chan, 10000))
		;

	ast_deactivate_generator(chan);

	return -1;
}
예제 #19
0
static int waitfor_exec(struct ast_channel *chan, const char *data, int wait_for_silence)
{
	int res = 1;
	int timereqd = 1000;
	int timeout = 0;
	int iterations = 1, i;
	time_t waitstart;
	struct ast_silence_generator *silgen = NULL;

	if (chan->_state != AST_STATE_UP) {
		res = ast_answer(chan); /* Answer the channel */
	}

	if (!data || ( (sscanf(data, "%30d,%30d,%30d", &timereqd, &iterations, &timeout) != 3) &&
		(sscanf(data, "%30d,%30d", &timereqd, &iterations) != 2) &&
		(sscanf(data, "%30d", &timereqd) != 1) ) ) {
		ast_log(LOG_WARNING, "Using default value of 1000ms, 1 iteration, no timeout\n");
	}

	ast_verb(3, "Waiting %d time(s) for %d ms silence with %d timeout\n", iterations, timereqd, timeout);

	if (ast_opt_transmit_silence) {
		silgen = ast_channel_start_silence_generator(chan);
	}
	time(&waitstart);
	res = 1;
	for (i=0; (i<iterations) && (res == 1); i++) {
		res = do_waiting(chan, timereqd, waitstart, timeout, wait_for_silence);
	}
	if (silgen) {
		ast_channel_stop_silence_generator(chan, silgen);
	}


	if (res > 0)
		res = 0;
	return res;
}
예제 #20
0
/* Perform actual pickup between two channels */
static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
{
	int res = 0;

	if (option_debug)
		ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);

	if ((res = ast_answer(chan))) {
		ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
		return -1;
	}

	if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
		ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
		return -1;
	}

	if ((res = ast_channel_masquerade(target, chan))) {
		ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
		return -1;
	}

	return res;
}
예제 #21
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;
}
예제 #22
0
static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
	int volfactor, const int fd, struct spy_dtmf_options *user_options,
	const char *mygroup, const char *myenforced, const char *spec, const char *exten,
	const char *context, const char *mailbox, const char *name_context)
{
	char nameprefix[AST_NAME_STRLEN];
	char peer_name[AST_NAME_STRLEN + 5];
	char exitcontext[AST_MAX_CONTEXT] = "";
	signed char zero_volume = 0;
	int waitms;
	int res;
	char *ptr;
	int num;
	int num_spyed_upon = 1;
	struct ast_channel_iterator *iter = NULL;

	if (ast_test_flag(flags, OPTION_EXIT)) {
		const char *c;
		ast_channel_lock(chan);
		if ((c = pbx_builtin_getvar_helper(chan, "SPY_EXIT_CONTEXT"))) {
			ast_copy_string(exitcontext, c, sizeof(exitcontext));
		} else if (!ast_strlen_zero(chan->macrocontext)) {
			ast_copy_string(exitcontext, chan->macrocontext, sizeof(exitcontext));
		} else {
			ast_copy_string(exitcontext, chan->context, sizeof(exitcontext));
		}
		ast_channel_unlock(chan);
	}

	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	ast_set_flag(chan, AST_FLAG_SPYING); /* so nobody can spy on us while we are spying */

	waitms = 100;

	for (;;) {
		struct ast_autochan *autochan = NULL, *next_autochan = NULL;
		struct ast_channel *prev = NULL;

		if (!ast_test_flag(flags, OPTION_QUIET) && num_spyed_upon) {
			res = ast_streamfile(chan, "beep", chan->language);
			if (!res)
				res = ast_waitstream(chan, "");
			else if (res < 0) {
				ast_clear_flag(chan, AST_FLAG_SPYING);
				break;
			}
			if (!ast_strlen_zero(exitcontext)) {
				char tmp[2];
				tmp[0] = res;
				tmp[1] = '\0';
				if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
					goto exit;
				else
					ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
			}
		}

		/* Set up the iterator we'll be using during this call */
		if (!ast_strlen_zero(spec)) {
			iter = ast_channel_iterator_by_name_new(spec, strlen(spec));
		} else if (!ast_strlen_zero(exten)) {
			iter = ast_channel_iterator_by_exten_new(exten, context);
		} else {
			iter = ast_channel_iterator_all_new();
		}

		if (!iter) {
			return -1;
		}

		res = ast_waitfordigit(chan, waitms);
		if (res < 0) {
			ast_clear_flag(chan, AST_FLAG_SPYING);
			break;
		}
		if (!ast_strlen_zero(exitcontext)) {
			char tmp[2];
			tmp[0] = res;
			tmp[1] = '\0';
			if (!ast_goto_if_exists(chan, exitcontext, tmp, 1))
				goto exit;
			else
				ast_debug(2, "Exit by single digit did not work in chanspy. Extension %s does not exist in context %s\n", tmp, exitcontext);
		}

		/* reset for the next loop around, unless overridden later */
		waitms = 100;
		num_spyed_upon = 0;

		for (autochan = next_channel(iter, autochan, chan);
		     autochan;
			 prev = autochan->chan, ast_autochan_destroy(autochan),
		     autochan = next_autochan ? next_autochan : 
				next_channel(iter, autochan, chan), next_autochan = NULL) {
			int igrp = !mygroup;
			int ienf = !myenforced;
			char *s;

			if (autochan->chan == prev) {
				ast_autochan_destroy(autochan);
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_autochan_destroy(autochan);
				break;
			}

			if (ast_test_flag(flags, OPTION_BRIDGED) && !ast_bridged_channel(autochan->chan)) {
				continue;
			}

			if (ast_check_hangup(autochan->chan) || ast_test_flag(autochan->chan, AST_FLAG_SPYING)) {
				continue;
			}

			if (mygroup) {
				int num_groups = 0;
				int num_mygroups = 0;
				char dup_group[512];
				char dup_mygroup[512];
				char *groups[NUM_SPYGROUPS];
				char *mygroups[NUM_SPYGROUPS];
				const char *group = NULL;
				int x;
				int y;
				ast_copy_string(dup_mygroup, mygroup, sizeof(dup_mygroup));
				num_mygroups = ast_app_separate_args(dup_mygroup, ':', mygroups,
					ARRAY_LEN(mygroups));

				/* Before dahdi scan was part of chanspy, it would use the "GROUP" variable 
				 * rather than "SPYGROUP", this check is done to preserve expected behavior */
				if (ast_test_flag(flags, OPTION_DAHDI_SCAN)) {
					group = pbx_builtin_getvar_helper(autochan->chan, "GROUP");
				} else {
					group = pbx_builtin_getvar_helper(autochan->chan, "SPYGROUP");
				}

				if (!ast_strlen_zero(group)) {
					ast_copy_string(dup_group, group, sizeof(dup_group));
					num_groups = ast_app_separate_args(dup_group, ':', groups,
						ARRAY_LEN(groups));
				}

				for (y = 0; y < num_mygroups; y++) {
					for (x = 0; x < num_groups; x++) {
						if (!strcmp(mygroups[y], groups[x])) {
							igrp = 1;
							break;
						}
					}
				}
			}

			if (!igrp) {
				continue;
			}
			if (myenforced) {
				char ext[AST_CHANNEL_NAME + 3];
				char buffer[512];
				char *end;

				snprintf(buffer, sizeof(buffer) - 1, ":%s:", myenforced);

				ast_copy_string(ext + 1, autochan->chan->name, sizeof(ext) - 1);
				if ((end = strchr(ext, '-'))) {
					*end++ = ':';
					*end = '\0';
				}

				ext[0] = ':';

				if (strcasestr(buffer, ext)) {
					ienf = 1;
				}
			}

			if (!ienf) {
				continue;
			}

			strcpy(peer_name, "spy-");
			strncat(peer_name, autochan->chan->name, AST_NAME_STRLEN - 4 - 1);
			ptr = strchr(peer_name, '/');
			*ptr++ = '\0';
			ptr = strsep(&ptr, "-");

			for (s = peer_name; s < ptr; s++)
				*s = tolower(*s);

			if (!ast_test_flag(flags, OPTION_QUIET)) {
				if (ast_test_flag(flags, OPTION_NAME)) {
					const char *local_context = S_OR(name_context, "default");
					const char *local_mailbox = S_OR(mailbox, ptr);
					res = ast_app_sayname(chan, local_mailbox, local_context);
				}
				if (!ast_test_flag(flags, OPTION_NAME) || res < 0) {
					if (!ast_test_flag(flags, OPTION_NOTECH)) {
						if (ast_fileexists(peer_name, NULL, NULL) > 0) {
							res = ast_streamfile(chan, peer_name, chan->language);
							if (!res) {
								res = ast_waitstream(chan, "");
							}
							if (res) {
								ast_autochan_destroy(autochan);
								break;
							}
						} else {
							res = ast_say_character_str(chan, peer_name, "", chan->language);
						}
					}
					if ((num = atoi(ptr)))
						ast_say_digits(chan, atoi(ptr), "", chan->language);
				}
			}

			res = channel_spy(chan, autochan, &volfactor, fd, user_options, flags, exitcontext);
			num_spyed_upon++;

			if (res == -1) {
				ast_autochan_destroy(autochan);
				goto exit;
			} else if (res == -2) {
				res = 0;
				ast_autochan_destroy(autochan);
				goto exit;
			} else if (res > 1 && spec) {
				struct ast_channel *next;

				snprintf(nameprefix, AST_NAME_STRLEN, "%s/%d", spec, res);

				if ((next = ast_channel_get_by_name_prefix(nameprefix, strlen(nameprefix)))) {
					next_autochan = ast_autochan_setup(next);
					next = ast_channel_unref(next);
				} else {
					/* stay on this channel, if it is still valid */
					if (!ast_check_hangup(autochan->chan)) {
						next_autochan = ast_autochan_setup(autochan->chan);
					} else {
						/* the channel is gone */
						next_autochan = NULL;
					}
				}
			} else if (res == 0 && ast_test_flag(flags, OPTION_EXITONHANGUP)) {
				goto exit;
			}
		}

		iter = ast_channel_iterator_destroy(iter);

		if (res == -1 || ast_check_hangup(chan))
			break;
		if (ast_test_flag(flags, OPTION_STOP) && !next_autochan) {
			break;
		}
	}
exit:

	ast_clear_flag(chan, AST_FLAG_SPYING);

	ast_channel_setoption(chan, AST_OPTION_TXGAIN, &zero_volume, sizeof(zero_volume), 0);

	return res;
}
예제 #23
0
static int testserver_exec(struct ast_channel *chan, const char *data)
{
    int res = 0;
    char testid[80]="";
    char fn[80];
    FILE *f;
    if (ast_channel_state(chan) != AST_STATE_UP)
        res = ast_answer(chan);
    /* Read version */
    ast_debug(1, "Read client version\n");
    if (!res)
        res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
    if (res > 0)
        res = 0;

    ast_debug(1, "client version: %s\n", testid);
    ast_debug(1, "Transmit server version\n");

    res = ast_safe_sleep(chan, 1000);
    if (!res)
        res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0);
    if (res > 0)
        res = 0;

    if (!res)
        res = ast_app_getdata(chan, NULL, testid, sizeof(testid) - 1, 0);
    ast_debug(1, "read test identifier: %s\n", testid);
    /* Check for sneakyness */
    if (strchr(testid, '/'))
        res = -1;
    if ((res >=0) && (!ast_strlen_zero(testid))) {
        /* Got a Test ID!  Whoo hoo! */
        /* Make the directory to hold the test results in case it's not there */
        snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
        ast_mkdir(fn, 0777);
        snprintf(fn, sizeof(fn), "%s/testresults/%s-server.txt", ast_config_AST_LOG_DIR, testid);
        if ((f = fopen(fn, "w+"))) {
            setlinebuf(f);
            fprintf(f, "SERVERCHAN:    %s\n", ast_channel_name(chan));
            fprintf(f, "SERVERTEST ID: %s\n", testid);
            fprintf(f, "ANSWER:        PASS\n");
            ast_debug(1, "Processing Test ID '%s'\n", testid);
            res = ast_safe_sleep(chan, 1000);
            if (!res) {
                /* Step 1: Send "1" */
                ast_debug(1, "TestServer: 1.  Send DTMF 1\n");
                res = ast_dtmf_stream(chan, NULL, "1", 0,0 );
                fprintf(f, "SEND DTMF 1:   %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 2: Wait for "2" */
                ast_debug(1, "TestServer: 2.  Wait DTMF 2\n");
                res = ast_waitfordigit(chan, 3000);
                fprintf(f, "WAIT DTMF 2:   %s\n", (res != '2') ? "FAIL" : "PASS");
                if (res == '2')
                    res = 0;
                else
                    res = -1;
            }
            if (!res) {
                /* Step 3: Measure noise */
                ast_debug(1, "TestServer: 3.  Measure noise\n");
                res = measurenoise(chan, 6000, "TestServer");
                fprintf(f, "MEASURENOISE:  %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 4: Send "4" */
                ast_debug(1, "TestServer: 4.  Send DTMF 4\n");
                res = ast_dtmf_stream(chan, NULL, "4", 0, 0);
                fprintf(f, "SEND DTMF 4:   %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 5: Wait one second */
                ast_debug(1, "TestServer: 5.  Wait one second\n");
                res = ast_safe_sleep(chan, 1000);
                fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 6: Measure noise */
                ast_debug(1, "TestServer: 6.  Measure tone\n");
                res = measurenoise(chan, 4000, "TestServer");
                fprintf(f, "MEASURETONE:   %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 7: Send "5" */
                ast_debug(1, "TestServer: 7.  Send DTMF 5\n");
                res = ast_dtmf_stream(chan, NULL, "5", 0, 0);
                fprintf(f, "SEND DTMF 5:   %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 8: Transmit tone noise */
                ast_debug(1, "TestServer: 8.  Transmit tone\n");
                res = sendnoise(chan, 6000);
                fprintf(f, "SENDTONE:      %s\n", (res < 0) ? "FAIL" : "PASS");
            }

            if (!res || (res == '7')) {
                /* Step 9: Wait for "7" */
                ast_debug(1, "TestServer: 9.  Wait DTMF 7\n");
                if (!res)
                    res = ast_waitfordigit(chan, 3000);
                fprintf(f, "WAIT DTMF 7:   %s\n", (res != '7') ? "FAIL" : "PASS");
                if (res == '7')
                    res = 0;
                else
                    res = -1;
            }
            if (!res) {
                res = ast_safe_sleep(chan, 1000);
            }
            if (!res) {
                /* Step 10: Send "8" */
                ast_debug(1, "TestServer: 10.  Send DTMF 8\n");
                res = ast_dtmf_stream(chan, NULL, "8", 0, 0);
                fprintf(f, "SEND DTMF 8:   %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 11: Wait for hangup to arrive! */
                ast_debug(1, "TestServer: 11.  Waiting for hangup\n");
                res = ast_safe_sleep(chan, 10000);
                fprintf(f, "WAIT HANGUP:   %s\n", (res < 0) ? "PASS" : "FAIL");
            }

            ast_log(LOG_NOTICE, "-- TEST COMPLETE--\n");
            fprintf(f, "-- END TEST--\n");
            fclose(f);
            res = -1;
        } else
            res = -1;
    } else {
        ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", ast_channel_name(chan));
        res = -1;
    }
    return res;
}
예제 #24
0
static int testclient_exec(struct ast_channel *chan, const char *data)
{
    int res = 0;
    const char *testid=data;
    char fn[80];
    char serverver[80];
    FILE *f;

    /* Check for test id */
    if (ast_strlen_zero(testid)) {
        ast_log(LOG_WARNING, "TestClient requires an argument - the test id\n");
        return -1;
    }

    if (ast_channel_state(chan) != AST_STATE_UP)
        res = ast_answer(chan);

    /* Wait a few just to be sure things get started */
    res = ast_safe_sleep(chan, 3000);
    /* Transmit client version */
    if (!res)
        res = ast_dtmf_stream(chan, NULL, "8378*1#", 0, 0);
    ast_debug(1, "Transmit client version\n");

    /* Read server version */
    ast_debug(1, "Read server version\n");
    if (!res)
        res = ast_app_getdata(chan, NULL, serverver, sizeof(serverver) - 1, 0);
    if (res > 0)
        res = 0;
    ast_debug(1, "server version: %s\n", serverver);

    if (res > 0)
        res = 0;

    if (!res)
        res = ast_safe_sleep(chan, 1000);
    /* Send test id */
    if (!res)
        res = ast_dtmf_stream(chan, NULL, testid, 0, 0);
    if (!res)
        res = ast_dtmf_stream(chan, NULL, "#", 0, 0);
    ast_debug(1, "send test identifier: %s\n", testid);

    if ((res >=0) && (!ast_strlen_zero(testid))) {
        /* Make the directory to hold the test results in case it's not there */
        snprintf(fn, sizeof(fn), "%s/testresults", ast_config_AST_LOG_DIR);
        ast_mkdir(fn, 0777);
        snprintf(fn, sizeof(fn), "%s/testresults/%s-client.txt", ast_config_AST_LOG_DIR, testid);
        if ((f = fopen(fn, "w+"))) {
            setlinebuf(f);
            fprintf(f, "CLIENTCHAN:    %s\n", ast_channel_name(chan));
            fprintf(f, "CLIENTTEST ID: %s\n", testid);
            fprintf(f, "ANSWER:        PASS\n");
            res = 0;

            if (!res) {
                /* Step 1: Wait for "1" */
                ast_debug(1, "TestClient: 2.  Wait DTMF 1\n");
                res = ast_waitfordigit(chan, 3000);
                fprintf(f, "WAIT DTMF 1:   %s\n", (res != '1') ? "FAIL" : "PASS");
                if (res == '1')
                    res = 0;
                else
                    res = -1;
            }
            if (!res) {
                res = ast_safe_sleep(chan, 1000);
            }
            if (!res) {
                /* Step 2: Send "2" */
                ast_debug(1, "TestClient: 2.  Send DTMF 2\n");
                res = ast_dtmf_stream(chan, NULL, "2", 0, 0);
                fprintf(f, "SEND DTMF 2:   %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 3: Wait one second */
                ast_debug(1, "TestClient: 3.  Wait one second\n");
                res = ast_safe_sleep(chan, 1000);
                fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 4: Measure noise */
                ast_debug(1, "TestClient: 4.  Measure noise\n");
                res = measurenoise(chan, 5000, "TestClient");
                fprintf(f, "MEASURENOISE:  %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 5: Wait for "4" */
                ast_debug(1, "TestClient: 5.  Wait DTMF 4\n");
                res = ast_waitfordigit(chan, 3000);
                fprintf(f, "WAIT DTMF 4:   %s\n", (res != '4') ? "FAIL" : "PASS");
                if (res == '4')
                    res = 0;
                else
                    res = -1;
            }
            if (!res) {
                /* Step 6: Transmit tone noise */
                ast_debug(1, "TestClient: 6.  Transmit tone\n");
                res = sendnoise(chan, 6000);
                fprintf(f, "SENDTONE:      %s\n", (res < 0) ? "FAIL" : "PASS");
            }
            if (!res || (res == '5')) {
                /* Step 7: Wait for "5" */
                ast_debug(1, "TestClient: 7.  Wait DTMF 5\n");
                if (!res)
                    res = ast_waitfordigit(chan, 3000);
                fprintf(f, "WAIT DTMF 5:   %s\n", (res != '5') ? "FAIL" : "PASS");
                if (res == '5')
                    res = 0;
                else
                    res = -1;
            }
            if (!res) {
                /* Step 8: Wait one second */
                ast_debug(1, "TestClient: 8.  Wait one second\n");
                res = ast_safe_sleep(chan, 1000);
                fprintf(f, "WAIT 1 SEC:    %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 9: Measure noise */
                ast_debug(1, "TestClient: 9.  Measure tone\n");
                res = measurenoise(chan, 4000, "TestClient");
                fprintf(f, "MEASURETONE:   %s (%d)\n", (res < 0) ? "FAIL" : "PASS", res);
                if (res > 0)
                    res = 0;
            }
            if (!res) {
                /* Step 10: Send "7" */
                ast_debug(1, "TestClient: 10.  Send DTMF 7\n");
                res = ast_dtmf_stream(chan, NULL, "7", 0, 0);
                fprintf(f, "SEND DTMF 7:   %s\n", (res < 0) ? "FAIL" : "PASS");
                if (res > 0)
                    res =0;
            }
            if (!res) {
                /* Step 11: Wait for "8" */
                ast_debug(1, "TestClient: 11.  Wait DTMF 8\n");
                res = ast_waitfordigit(chan, 3000);
                fprintf(f, "WAIT DTMF 8:   %s\n", (res != '8') ? "FAIL" : "PASS");
                if (res == '8')
                    res = 0;
                else
                    res = -1;
            }
            if (!res) {
                res = ast_safe_sleep(chan, 1000);
            }
            if (!res) {
                /* Step 12: Hangup! */
                ast_debug(1, "TestClient: 12.  Hangup\n");
            }

            ast_debug(1, "-- TEST COMPLETE--\n");
            fprintf(f, "-- END TEST--\n");
            fclose(f);
            res = -1;
        } else
            res = -1;
    } else {
        ast_log(LOG_NOTICE, "Did not read a test ID on '%s'\n", ast_channel_name(chan));
        res = -1;
    }
    return res;
}
예제 #25
0
static int txfax_exec(struct ast_channel *chan, void *data)
{
    int res = 0;
    char source_file[256];
    char *x;
    char *s;
    char *t;
    char *v;
    int option;
    int len;
    t30_state_t fax;
    int calling_party;
    int verbose;
    int samples;
    
    struct localuser *u;
    struct ast_frame *inf = NULL;
    struct ast_frame outf;

    int original_read_fmt;
    int original_write_fmt;
    
    uint8_t __buf[sizeof(uint16_t)*MAX_BLOCK_SIZE + 2*AST_FRIENDLY_OFFSET];
    uint8_t *buf = __buf + AST_FRIENDLY_OFFSET;

    if (chan == NULL)
    {
        ast_log(LOG_WARNING, "Fax transmit channel is NULL. Giving up.\n");
        return -1;
    }

    span_set_message_handler(span_message);

    /* The next few lines of code parse out the filename and header from the input string */
    if (data == NULL)
    {
        /* No data implies no filename or anything is present */
        ast_log(LOG_WARNING, "Txfax requires an argument (filename)\n");
        return -1;
    }
    
    calling_party = FALSE;
    verbose = FALSE;
    source_file[0] = '\0'; 

    for (option = 0, v = s = data;  v;  option++, s++)
    {
        t = s;
        v = strchr(s, '|');
        s = (v)  ?  v  :  s + strlen(s);
        strncpy((char *) buf, t, s - t);
        buf[s - t] = '\0';
        if (option == 0)
        {
            /* The first option is always the file name */
            len = s - t;
            if (len > 255)
                len = 255;
            strncpy(source_file, t, len);
            source_file[len] = '\0';
        }
        else if (strncmp("caller", t, s - t) == 0)
        {
            calling_party = TRUE;
        }
        else if (strncmp("debug", t, s - t) == 0)
        {
            verbose = TRUE;
        }
    }

    /* Done parsing */

    LOCAL_USER_ADD(u);

    if (chan->_state != AST_STATE_UP)
    {
        /* Shouldn't need this, but checking to see if channel is already answered
         * Theoretically asterisk should already have answered before running the app */
        res = ast_answer(chan);
    }
    
    if (!res)
    {
        original_read_fmt = chan->readformat;
        if (original_read_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
            if (res < 0)
            {
                ast_log(LOG_WARNING, "Unable to set to linear read mode, giving up\n");
                return -1;
            }
        }
        original_write_fmt = chan->writeformat;
        if (original_write_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
            if (res < 0)
            {
                ast_log(LOG_WARNING, "Unable to set to linear write mode, giving up\n");
                res = ast_set_read_format(chan, original_read_fmt);
                if (res)
                    ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
                return -1;
            }
        }
        fax_init(&fax, calling_party, NULL);
        if (verbose)
	    fax.logging.level = SPAN_LOG_SHOW_SEVERITY | SPAN_LOG_SHOW_PROTOCOL | SPAN_LOG_FLOW;

        x = pbx_builtin_getvar_helper(chan, "LOCALSTATIONID");
        if (x  &&  x[0])
            t30_set_local_ident(&fax, x);
        x = pbx_builtin_getvar_helper(chan, "LOCALHEADERINFO");
        if (x  &&  x[0])
            t30_set_header_info(&fax, x);
        t30_set_tx_file(&fax, source_file, -1, -1);
        //t30_set_phase_b_handler(&fax, phase_b_handler, chan);
        //t30_set_phase_d_handler(&fax, phase_d_handler, chan);
        t30_set_phase_e_handler(&fax, phase_e_handler, chan);
        while (ast_waitfor(chan, -1) > -1)
        {
            inf = ast_read(chan);
            if (inf == NULL)
            {
                res = -1;
                break;
            }
            if (inf->frametype == AST_FRAME_VOICE)
            {
                if (fax_rx(&fax, inf->data, inf->samples))
                    break;
                samples = (inf->samples <= MAX_BLOCK_SIZE)  ?  inf->samples  :  MAX_BLOCK_SIZE;
                len = fax_tx(&fax, (int16_t *) &buf[AST_FRIENDLY_OFFSET], samples);
                if (len)
                {
                    memset(&outf, 0, sizeof(outf));
                    outf.frametype = AST_FRAME_VOICE;
                    outf.subclass = AST_FORMAT_SLINEAR;
                    outf.datalen = len*sizeof(int16_t);
                    outf.samples = len;
                    outf.data = &buf[AST_FRIENDLY_OFFSET];
                    outf.offset = AST_FRIENDLY_OFFSET;
                    if (ast_write(chan, &outf) < 0)
                    {
                        ast_log(LOG_WARNING, "Unable to write frame to channel; %s\n", strerror(errno));
                        break;
                    }
                }
            }
            ast_frfree(inf);
        }
        if (inf == NULL)
        {
            ast_log(LOG_DEBUG, "Got hangup\n");
            res = -1;
        }
        if (original_read_fmt && original_read_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_read_format(chan, original_read_fmt);
            if (res)
                ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", chan->name);
        }
        if (original_write_fmt && original_write_fmt != AST_FORMAT_SLINEAR)
        {
            res = ast_set_write_format(chan, original_write_fmt);
            if (res)
                ast_log(LOG_WARNING, "Unable to restore write format on '%s'\n", chan->name);
        }
        fax_release(&fax);
    }
    else
    {
        ast_log(LOG_WARNING, "Could not answer channel '%s'\n", chan->name);
    }
    LOCAL_USER_REMOVE(u);
    return res;
}
예제 #26
0
/*!
 * \brief This is the main function called by Asterisk Core whenever the App is invoked in the extension logic.
 *
 * \param chan Asterisk Channel
 * \param data Application data
 *
 * \retval 0 success
 * \retval -1 failure
 */
static int alarmreceiver_exec(struct ast_channel *chan, const char *data)
{
	int res = 0;
	int no_checksum = 0;
	event_node_t *elp, *efree;
	char signalling_type[64] = "";
	event_node_t *event_head = NULL;

	if ((ast_format_cmp(ast_channel_writeformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
		(ast_format_cmp(ast_channel_writeformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
		ast_verb(4, "AlarmReceiver: Setting write format to Mu-law\n");
		if (ast_set_write_format(chan, ast_format_ulaw)) {
			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set write format to Mu-law on %s\n",ast_channel_name(chan));
			return -1;
		}
	}

	if ((ast_format_cmp(ast_channel_readformat(chan), ast_format_ulaw) == AST_FORMAT_CMP_NOT_EQUAL) &&
		(ast_format_cmp(ast_channel_readformat(chan), ast_format_alaw) == AST_FORMAT_CMP_NOT_EQUAL)) {
		ast_verb(4, "AlarmReceiver: Setting read format to Mu-law\n");
		if (ast_set_read_format(chan, ast_format_ulaw)) {
			ast_log(LOG_WARNING, "AlarmReceiver: Unable to set read format to Mu-law on %s\n",ast_channel_name(chan));
			return -1;
		}
	}

	/* Set default values for this invocation of the application */
	ast_copy_string(signalling_type, UNKNOWN_FORMAT, sizeof(signalling_type));
	call_start_time = ast_tvnow();

	/* Answer the channel if it is not already */
	if (ast_channel_state(chan) != AST_STATE_UP) {
		ast_verb(4, "AlarmReceiver: Answering channel\n");
		if (ast_answer(chan)) {
			return -1;
		}
	}

	/* Wait for the connection to settle post-answer */
	ast_verb(4, "AlarmReceiver: Waiting for connection to stabilize\n");
	if (ast_safe_sleep(chan, answait)) {
		return -1;
	}

	/* Attempt to receive the events */
	receive_ademco_event(chan, &event_head, signalling_type, &no_checksum);

	/* Events queued by receiver, write them all out here if so configured */
	if (!log_individual_events) {
		res = log_events(chan, signalling_type, event_head, no_checksum);
	}

	/* Do we exec a command line at the end? */
	if ((!res) && (!ast_strlen_zero(event_app)) && (event_head)) {
		ast_debug(1,"Alarmreceiver: executing: %s\n", event_app);
		ast_safe_system(event_app);
	}

	/* Free up the data allocated in our linked list */
	for (elp = event_head; (elp != NULL);) {
		efree = elp;
		elp = elp->next;
		ast_free(efree);
	}

	return 0;
}
예제 #27
0
/*! \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;
}
예제 #28
0
static int app_exec(struct ast_channel *chan, void *data)
{
	struct ast_module_user *lu;
	struct playlist_entry *entry;
	const char *args = data;
	int child_stdin[2] = { 0,0 };
	int child_stdout[2] = { 0,0 };
	int child_stderr[2] = { 0,0 };
	int res = -1;
	int test_available_fd = -1;
	int gen_active = 0;
	int pid;
	char *argv[32];
	int argc = 1;
	char *buf, *command;
	FILE *child_commands = NULL;
	FILE *child_errors = NULL;
	FILE *child_events = NULL;
	struct ivr_localuser foo = {
		.playlist = AST_LIST_HEAD_INIT_VALUE,
		.finishlist = AST_LIST_HEAD_INIT_VALUE,
	};
	struct ivr_localuser *u = &foo;
	sigset_t fullset, oldset;

	lu = ast_module_user_add(chan);

	sigfillset(&fullset);
	pthread_sigmask(SIG_BLOCK, &fullset, &oldset);

	u->abort_current_sound = 0;
	u->chan = chan;
	
	if (ast_strlen_zero(args)) {
		ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
		ast_module_user_remove(lu);
		return -1;	
	}

	buf = ast_strdupa(data);

	argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));

	if (pipe(child_stdin)) {
		ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
		goto exit;
	}

	if (pipe(child_stdout)) {
		ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
		goto exit;
	}

	if (pipe(child_stderr)) {
		ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
		goto exit;
	}

	if (chan->_state != AST_STATE_UP) {
		ast_answer(chan);
	}

	if (ast_activate_generator(chan, &gen, u) < 0) {
		ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
		goto exit;
	} else
		gen_active = 1;

	pid = fork();
	if (pid < 0) {
		ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
		goto exit;
	}

	if (!pid) {
		/* child process */
		int i;

		signal(SIGPIPE, SIG_DFL);
		pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);

		if (ast_opt_high_priority)
			ast_set_priority(0);

		dup2(child_stdin[0], STDIN_FILENO);
		dup2(child_stdout[1], STDOUT_FILENO);
		dup2(child_stderr[1], STDERR_FILENO);
		for (i = STDERR_FILENO + 1; i < 1024; i++)
			close(i);
		execv(argv[0], argv);
		fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno));
		_exit(1);
	} else {
		/* parent process */
		int child_events_fd = child_stdin[1];
		int child_commands_fd = child_stdout[0];
		int child_errors_fd = child_stderr[0];
		struct ast_frame *f;
		int ms;
		int exception;
		int ready_fd;
		int waitfds[2] = { child_errors_fd, child_commands_fd };
		struct ast_channel *rchan;

		pthread_sigmask(SIG_SETMASK, &oldset, NULL);

		close(child_stdin[0]);
		child_stdin[0] = 0;
		close(child_stdout[1]);
		child_stdout[1] = 0;
		close(child_stderr[1]);
		child_stderr[1] = 0;

		if (!(child_events = fdopen(child_events_fd, "w"))) {
			ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n");
			goto exit;
		}

		if (!(child_commands = fdopen(child_commands_fd, "r"))) {
			ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n");
			goto exit;
		}

		if (!(child_errors = fdopen(child_errors_fd, "r"))) {
			ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n");
			goto exit;
		}

		test_available_fd = open("/dev/null", O_RDONLY);

		setvbuf(child_events, NULL, _IONBF, 0);
		setvbuf(child_commands, NULL, _IONBF, 0);
		setvbuf(child_errors, NULL, _IONBF, 0);

		res = 0;

		while (1) {
			if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
				ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
				res = -1;
				break;
			}

			if (ast_check_hangup(chan)) {
				ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
				send_child_event(child_events, 'H', NULL, chan);
				res = -1;
				break;
			}

			ready_fd = 0;
			ms = 100;
			errno = 0;
			exception = 0;

			rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms);

			if (!AST_LIST_EMPTY(&u->finishlist)) {
				AST_LIST_LOCK(&u->finishlist);
				while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
					send_child_event(child_events, 'F', entry->filename, chan);
					free(entry);
				}
				AST_LIST_UNLOCK(&u->finishlist);
			}

			if (rchan) {
				/* the channel has something */
				f = ast_read(chan);
				if (!f) {
					ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
					send_child_event(child_events, 'H', NULL, chan);
					res = -1;
					break;
				}

				if (f->frametype == AST_FRAME_DTMF) {
					send_child_event(child_events, f->subclass, NULL, chan);
					if (u->option_autoclear) {
						if (!u->abort_current_sound && !u->playing_silence)
							send_child_event(child_events, 'T', NULL, chan);
						AST_LIST_LOCK(&u->playlist);
						while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
							send_child_event(child_events, 'D', entry->filename, chan);
							free(entry);
						}
						if (!u->playing_silence)
							u->abort_current_sound = 1;
						AST_LIST_UNLOCK(&u->playlist);
					}
				} else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
					ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
					send_child_event(child_events, 'H', NULL, chan);
					ast_frfree(f);
					res = -1;
					break;
				}
				ast_frfree(f);
			} else if (ready_fd == child_commands_fd) {
				char input[1024];

				if (exception || feof(child_commands)) {
					ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
					res = -1;
					break;
				}

				if (!fgets(input, sizeof(input), child_commands))
					continue;

				command = ast_strip(input);

				ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input);

				if (strlen(input) < 4)
					continue;

				if (input[0] == 'S') {
					if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
						ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
						send_child_event(child_events, 'Z', NULL, chan);
						strcpy(&input[2], "exception");
					}
					if (!u->abort_current_sound && !u->playing_silence)
						send_child_event(child_events, 'T', NULL, chan);
					AST_LIST_LOCK(&u->playlist);
					while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
						send_child_event(child_events, 'D', entry->filename, chan);
						free(entry);
					}
					if (!u->playing_silence)
						u->abort_current_sound = 1;
					entry = make_entry(&input[2]);
					if (entry)
						AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
					AST_LIST_UNLOCK(&u->playlist);
				} else if (input[0] == 'A') {
					if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
						ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
						send_child_event(child_events, 'Z', NULL, chan);
						strcpy(&input[2], "exception");
					}
					entry = make_entry(&input[2]);
					if (entry) {
						AST_LIST_LOCK(&u->playlist);
						AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
						AST_LIST_UNLOCK(&u->playlist);
					}
				} else if (input[0] == 'H') {
					ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
					send_child_event(child_events, 'H', NULL, chan);
					break;
				} else if (input[0] == 'O') {
					if (!strcasecmp(&input[2], "autoclear"))
						u->option_autoclear = 1;
					else if (!strcasecmp(&input[2], "noautoclear"))
						u->option_autoclear = 0;
					else
						ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
				}
			} else if (ready_fd == child_errors_fd) {
				char input[1024];

				if (exception || (dup2(child_commands_fd, test_available_fd) == -1) || feof(child_errors)) {
					ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
					res = -1;
					break;
				}

				if (fgets(input, sizeof(input), child_errors)) {
					command = ast_strip(input);
					ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
				}
			} else if ((ready_fd < 0) && ms) { 
				if (errno == 0 || errno == EINTR)
					continue;

				ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
				break;
			}
		}
	}

 exit:
	if (gen_active)
		ast_deactivate_generator(chan);

	if (child_events)
		fclose(child_events);

	if (child_commands)
		fclose(child_commands);

	if (child_errors)
		fclose(child_errors);

	if (test_available_fd > -1) {
		close(test_available_fd);
	}

	if (child_stdin[0])
		close(child_stdin[0]);

	if (child_stdin[1])
		close(child_stdin[1]);

	if (child_stdout[0])
		close(child_stdout[0]);

	if (child_stdout[1])
		close(child_stdout[1]);

	if (child_stderr[0])
		close(child_stderr[0]);

	if (child_stderr[1])
		close(child_stderr[1]);

	while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
		free(entry);

	ast_module_user_remove(lu);

	return res;
}
예제 #29
0
/*--- conf_exec: The meetme() application */
static int conf_exec(struct ast_channel *chan, void *data)
{
	int res=-1;
	struct localuser *u;
	char confno[AST_MAX_EXTENSION] = "";
	int allowretry = 0;
	int retrycnt = 0;
	struct ast_conference *cnf;
	int confflags = 0;
	int dynamic = 0;
	int empty = 0, empty_no_pin = 0;
	char *notdata, *info, *inflags = NULL, *inpin = NULL, the_pin[AST_MAX_EXTENSION] = "";

	if (!data || ast_strlen_zero(data)) {
		allowretry = 1;
		notdata = "";
	} else {
		notdata = data;
	}
	LOCAL_USER_ADD(u);
	if (chan->_state != AST_STATE_UP)
		ast_answer(chan);

	info = ast_strdupa((char *)notdata);

	if (info) {
		char *tmp = strsep(&info, "|");
		strncpy(confno, tmp, sizeof(confno) - 1);
		if (ast_strlen_zero(confno)) {
			allowretry = 1;
		}
	}
	if (info)
		inflags = strsep(&info, "|");
	if (info)
		inpin = strsep(&info, "|");
	if (inpin)
		strncpy(the_pin, inpin, sizeof(the_pin) - 1);

	if (inflags) {
		if (strchr(inflags, 'a'))
			confflags |= CONFFLAG_ADMIN;
		if (strchr(inflags, 'm'))
			confflags |= CONFFLAG_MONITOR;
		if (strchr(inflags, 'p'))
			confflags |= CONFFLAG_POUNDEXIT;
		if (strchr(inflags, 's'))
			confflags |= CONFFLAG_STARMENU;
		if (strchr(inflags, 't'))
			confflags |= CONFFLAG_TALKER;
		if (strchr(inflags, 'q'))
			confflags |= CONFFLAG_QUIET;
		if (strchr(inflags, 'M'))
			confflags |= CONFFLAG_MOH;
		if (strchr(inflags, 'x'))
			confflags |= CONFFLAG_MARKEDEXIT;
		if (strchr(inflags, 'X'))
			confflags |= CONFFLAG_EXIT_CONTEXT;
		if (strchr(inflags, 'A'))
			confflags |= CONFFLAG_MARKEDUSER;
		if (strchr(inflags, 'b'))
			confflags |= CONFFLAG_AGI;
		if (strchr(inflags, 'w'))
			confflags |= CONFFLAG_WAITMARKED;
		if (strchr(inflags, 'd'))
			dynamic = 1;
		if (strchr(inflags, 'D')) {
			dynamic = 1;
			if (! inpin) {
				strncpy(the_pin, "q", sizeof(the_pin) - 1);
			}
		}
		if (strchr(inflags, 'e'))
			empty = 1;
		if (strchr(inflags, 'E')) {
			empty = 1;
			empty_no_pin = 1;
		}
	}

	do {
		if (retrycnt > 3)
			allowretry = 0;
		if (empty) {
			int i, map[1024];
			struct ast_config *cfg;
			struct ast_variable *var;
			int confno_int;

			memset(map, 0, sizeof(map));

			ast_mutex_lock(&conflock);
			cnf = confs;
			while (cnf) {
				if (sscanf(cnf->confno, "%d", &confno_int) == 1) {
					/* Disqualify in use conference */
					if (confno_int >= 0 && confno_int < 1024)
						map[confno_int]++;
				}
				cnf = cnf->next;
			}
			ast_mutex_unlock(&conflock);

			/* We only need to load the config file for static and empty_no_pin (otherwise we don't care) */
			if ((empty_no_pin) || (!dynamic)) {
				cfg = ast_load("meetme.conf");
				if (cfg) {
					var = ast_variable_browse(cfg, "rooms");
					while(var) {
						if (!strcasecmp(var->name, "conf")) {
							char *stringp = ast_strdupa(var->value);
							if (stringp) {
								char *confno_tmp = strsep(&stringp, "|,");
								int found = 0;
								if (sscanf(confno_tmp, "%d", &confno_int) == 1) {
									if ((confno_int >= 0) && (confno_int < 1024)) {
										if (stringp && empty_no_pin) {
											map[confno_int]++;
										}
									}
								}
								if (! dynamic) {
									/* For static:  run through the list and see if this conference is empty */
									ast_mutex_lock(&conflock);
									cnf = confs;
									while (cnf) {
										if (!strcmp(confno_tmp, cnf->confno)) {
											/* The conference exists, therefore it's not empty */
											found = 1;
											break;
										}
										cnf = cnf->next;
									}
									ast_mutex_unlock(&conflock);
									if (!found) {
										/* At this point, we have a confno_tmp (static conference) that is empty */
										if ((empty_no_pin && ((!stringp) || (stringp && (stringp[0] == '\0')))) || (!empty_no_pin)) {
										/* Case 1:  empty_no_pin and pin is nonexistant (NULL)
										 * Case 2:  empty_no_pin and pin is blank (but not NULL)
										 * Case 3:  not empty_no_pin
										 */
											strncpy(confno, confno_tmp, sizeof(confno) - 1);
											break;
											/* XXX the map is not complete (but we do have a confno) */
										}
									}
								}
							} else {
								ast_log(LOG_ERROR, "Out of memory\n");
							}
						}
						var = var->next;
					}
					ast_destroy(cfg);
				}
			}
			/* Select first conference number not in use */
			if (ast_strlen_zero(confno) && dynamic) {
				for (i=0;i<1024;i++) {
					if (!map[i]) {
						snprintf(confno, sizeof(confno), "%d", i);
						break;
					}
				}
			}

			/* Not found? */
			if (ast_strlen_zero(confno)) {
				res = ast_streamfile(chan, "conf-noempty", chan->language);
				if (!res)
					ast_waitstream(chan, "");
			} else {
				if (sscanf(confno, "%d", &confno_int) == 1) {
					res = ast_streamfile(chan, "conf-enteringno", chan->language);
					if (!res) {
						ast_waitstream(chan, "");
						res = ast_say_digits(chan, confno_int, "", chan->language);
					}
				} else {
					ast_log(LOG_ERROR, "Could not scan confno '%s'\n", confno);
				}
			}
		}
		while (allowretry && (ast_strlen_zero(confno)) && (++retrycnt < 4)) {
			/* Prompt user for conference number */
			res = ast_app_getdata(chan, "conf-getconfno", confno, sizeof(confno) - 1, 0);
			if (res < 0) {
				/* Don't try to validate when we catch an error */
				confno[0] = '\0';
				allowretry = 0;
				break;
			}
		}
		if (!ast_strlen_zero(confno)) {
			/* Check the validity of the conference */
			cnf = find_conf(chan, confno, 1, dynamic, the_pin);
			if (!cnf) {
				res = ast_streamfile(chan, "conf-invalid", chan->language);
				if (!res)
					ast_waitstream(chan, "");
				res = -1;
				if (allowretry)
					confno[0] = '\0';
			} else {
				if (!ast_strlen_zero(cnf->pin)) {
					char pin[AST_MAX_EXTENSION]="";
					int j;

					/* Allow the pin to be retried up to 3 times */
					for (j=0; j<3; j++) {
						if (*the_pin) {
							strncpy(pin, the_pin, sizeof(pin) - 1);
							res = 0;
						} else {
							/* Prompt user for pin if pin is required */
							res = ast_app_getdata(chan, "conf-getpin", pin + strlen(pin), sizeof(pin) - 1 - strlen(pin), 0);
						}
						if (res >= 0) {
							if (!strcasecmp(pin, cnf->pin)) {
								/* Pin correct */
								allowretry = 0;
								/* Run the conference */
								res = conf_run(chan, cnf, confflags);
								break;
							} else {
								/* Pin invalid */
								res = ast_streamfile(chan, "conf-invalidpin", chan->language);
								if (!res)
									ast_waitstream(chan, AST_DIGIT_ANY);
								if (res < 0)
									break;
								pin[0] = res;
								pin[1] = '\0';
								res = -1;
								if (allowretry)
									confno[0] = '\0';
							}
						} else {
							res = -1;
							allowretry = 0;
							break;
						}

						/* Don't retry pin with a static pin */
						if (*the_pin) {
							break;
						}
					}
				} else {
					/* No pin required */
					allowretry = 0;

					/* Run the conference */
					res = conf_run(chan, cnf, confflags);
				}
			}
		}
	} while (allowretry);
	/* Do the conference */
	LOCAL_USER_REMOVE(u);
	return res;
}
static int pickup_exec(struct ast_channel *chan, void *data)
{
	int res = 0;
	struct localuser *u = NULL;
	struct ast_channel *origin = NULL, *target = NULL;
	char *tmp = NULL, *exten = NULL, *context = NULL, *rest=data;
	char workspace[256] = "";
	const char *tmp2 = NULL;

	if (ast_strlen_zero(data)) {
		ast_log(LOG_WARNING, "Pickup requires an argument (extension) !\n");
		return -1;	
	}

	LOCAL_USER_ADD(u);
	
	while (!target && (exten = rest) ) {
		res = 0;
		rest = strchr(exten, '&');
		if (rest)
			*rest++ = 0;

		/* Get the extension and context if present */
		context = strchr(exten, '@');
		if (context)
			*context++ = '\0';

		/* If the context is the pickup mark, iterate through all channels finding the right origin one */
		if (!strcmp(context, PICKUPMARK)) {
			while ((origin = ast_channel_walk_locked(origin))) {
				if (origin) {
					tmp2 = pbx_builtin_getvar_helper(origin, PICKUPMARK);
					if (tmp2 && !strcmp(tmp2, exten))
						break;
					ast_mutex_unlock(&origin->lock);
				}
			}
		} else {
			/* Use the classic mode of searching */
			origin = ast_get_channel_by_exten_locked(exten, context);
		}

		if (origin) {
			ast_cdr_getvar(origin->cdr, "dstchannel", &tmp, workspace,
					sizeof(workspace), 0, 0);
			if (tmp) {
				/* We have a possible channel... now we need to find it! */
				target = ast_get_channel_by_name_locked(tmp);
			} else {
				ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
				res = -1;
			}
			ast_mutex_unlock(&origin->lock);

		} else {
			ast_log(LOG_DEBUG, "No originating channel found.\n");
		}

		if (res)
			continue;

		if (target && (!target->pbx) && ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING) ) ) {
			ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n", target->name,
					chan->name);
			res = ast_answer(chan);
			if (res) {
				ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
				res = -1;
				break;
			}
			res = ast_queue_control(chan, AST_CONTROL_ANSWER);
			if (res) {
				ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n",
						chan->name);
				res = -1;
				break;
			}
			res = ast_channel_masquerade(target, chan);
			if (res) {
				ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
				res = -1;
				break;
			}
		} else {
			ast_log(LOG_NOTICE, "No call pickup possible for %s...\n", exten);
			res = -1;
		}
	}
	if (target) 
		ast_mutex_unlock(&target->lock);
	
	LOCAL_USER_REMOVE(u);

	return res;
}