static void milliwatt_release(struct ast_channel *chan, void *data)
{
	ast_free(data);
	return;
}
Example #2
0
static void ari_bridges_play_new(const char *args_media,
	const char *args_lang,
	int args_offset_ms,
	int args_skipms,
	const char *args_playback_id,
	struct ast_ari_response *response,
	struct ast_bridge *bridge)
{
	RAII_VAR(struct ast_channel *, play_channel, NULL, ast_hangup);
	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
	RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);
	RAII_VAR(char *, playback_url, NULL, ast_free);

	struct stasis_topic *channel_topic;
	struct stasis_topic *bridge_topic;
	struct bridge_channel_control_thread_data *thread_data;
	pthread_t threadid;

	if (!(play_channel = prepare_bridge_media_channel("Announcer"))) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Could not create playback channel");
		return;
	}
	ast_debug(1, "Created announcer channel '%s'\n", ast_channel_name(play_channel));

	bridge_topic = ast_bridge_topic(bridge);
	channel_topic = ast_channel_topic(play_channel);

	/* Forward messages from the playback channel topic to the bridge topic so that anything listening for
	 * messages on the bridge topic will receive the playback start/stop messages. Other messages that would
	 * go to this channel will be suppressed since the channel is marked as internal.
	 */
	if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Could not forward playback channel stasis messages to bridge topic");
		return;
	}

	if (ast_unreal_channel_push_to_bridge(play_channel, bridge,
		AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Failed to put playback channel into the bridge");
		return;
	}

	control = stasis_app_control_create(play_channel);
	if (control == NULL) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	ao2_lock(control);
	if (ari_bridges_play_helper(args_media, args_lang, args_offset_ms,
			args_skipms, args_playback_id, response, bridge, control,
			&json, &playback_url)) {
		ao2_unlock(control);
		return;
	}
	ao2_unlock(control);

	if (stasis_app_bridge_playback_channel_add(bridge, play_channel, control)) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	/* Give play_channel and control reference to the thread data */
	thread_data = ast_calloc(1, sizeof(*thread_data));
	if (!thread_data) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	thread_data->bridge_channel = play_channel;
	thread_data->control = control;
	thread_data->forward = channel_forward;

	if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
		ast_ari_response_alloc_failed(response);
		ast_free(thread_data);
		return;
	}

	/* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
	play_channel = NULL;
	control = NULL;
	channel_forward = NULL;

	ast_ari_response_created(response, playback_url, ast_json_ref(json));
}
static int digest_create_request_with_auth(const struct ast_sip_auth_vector *auths,
	pjsip_rx_data *challenge, pjsip_tx_data *old_request, pjsip_tx_data **new_request)
{
	pjsip_auth_clt_sess auth_sess;
	pjsip_cseq_hdr *cseq;
	pj_status_t status;
	struct ast_sip_endpoint *endpoint;
	char *id = NULL;
	const char *id_type;
	pjsip_www_authenticate_hdr *auth_hdr;
	struct ast_str *realms;
	pjsip_dialog *dlg;

	dlg = pjsip_rdata_get_dlg(challenge);
	if (dlg) {
		endpoint = ast_sip_dialog_get_endpoint(dlg);
		id = endpoint ? ast_strdupa(ast_sorcery_object_get_id(endpoint)) : NULL;
		ao2_cleanup(endpoint);
		id_type = "Endpoint";
	}
	/* If there was no dialog, then this is probably a REGISTER so no endpoint */
	if (!id) {
		id = ast_alloca(strlen(challenge->pkt_info.src_name) + 7 /* ':' + port + NULL */);
		sprintf(id, "%s:%d", challenge->pkt_info.src_name, challenge->pkt_info.src_port);
		id_type = "Host";
	}

	auth_hdr = get_auth_header(challenge, NULL);
	if (auth_hdr == NULL) {
		ast_log(LOG_ERROR, "%s: '%s': Unable to find authenticate header in challenge.\n",
			id_type, id);
		return -1;
	}

	if (pjsip_auth_clt_init(&auth_sess, ast_sip_get_pjsip_endpoint(),
				old_request->pool, 0) != PJ_SUCCESS) {
		ast_log(LOG_ERROR, "%s: '%s': Failed to initialize client authentication session\n",
			id_type, id);
		return -1;
	}

	if (set_outbound_authentication_credentials(&auth_sess, auths, challenge, auth_hdr)) {
		ast_log(LOG_WARNING, "%s: '%s': Failed to set authentication credentials\n",
			id_type, id);
#if defined(HAVE_PJSIP_AUTH_CLT_DEINIT)
		/* In case it is not a noop here in the future. */
		pjsip_auth_clt_deinit(&auth_sess);
#endif
		return -1;
	}

	status = pjsip_auth_clt_reinit_req(&auth_sess, challenge, old_request, new_request);
#if defined(HAVE_PJSIP_AUTH_CLT_DEINIT)
	/* Release any cached auths */
	pjsip_auth_clt_deinit(&auth_sess);
#endif

	switch (status) {
	case PJ_SUCCESS:
		/* PJSIP creates a new transaction for new_request (meaning it creates a new
		 * branch). However, it recycles the Call-ID, from-tag, and CSeq from the
		 * original request. Some SIP implementations will not process the new request
		 * since the CSeq is the same as the original request. Incrementing it here
		 * fixes the interop issue
		 */
		cseq = pjsip_msg_find_hdr((*new_request)->msg, PJSIP_H_CSEQ, NULL);
		ast_assert(cseq != NULL);
		++cseq->cseq;
		return 0;
	case PJSIP_ENOCREDENTIAL:
		realms = ast_str_create(32);
		if (realms) {
			ast_str_append(&realms, 0, "%.*s", (int)auth_hdr->challenge.common.realm.slen,
				auth_hdr->challenge.common.realm.ptr);
			while((auth_hdr = get_auth_header(challenge, auth_hdr->next))) {
				ast_str_append(&realms, 0, ",%.*s", (int)auth_hdr->challenge.common.realm.slen,
					auth_hdr->challenge.common.realm.ptr);
			}
		}
		ast_log(LOG_WARNING,
			"%s: '%s': Unable to create request with auth. "
			"No auth credentials for realm(s) '%s' in challenge.\n", id_type, id,
			realms ? ast_str_buffer(realms) : "<unknown>");
		ast_free(realms);
		break;
	case PJSIP_EAUTHSTALECOUNT:
		ast_log(LOG_WARNING,
			"%s: '%s': Unable to create request with auth.  Number of stale retries exceeded.\n",
			id_type, id);
		break;
	case PJSIP_EFAILEDCREDENTIAL:
		ast_log(LOG_WARNING, "%s: '%s': Authentication credentials not accepted by server.\n",
			id_type, id);
		break;
	default:
		ast_log(LOG_WARNING, "%s: '%s': Unable to create request with auth. Unknown failure.\n",
			id_type, id);
		break;
	}

	return -1;
}
Example #4
0
char *ast_sip_cli_traverse_objects(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
	RAII_VAR(struct ao2_container *, container, NULL, ao2_cleanup);
	RAII_VAR(struct ast_sip_cli_formatter_entry *, formatter_entry, NULL, ao2_cleanup);
	RAII_VAR(void *, object, NULL, ao2_cleanup);
	int is_container = 0;
	const char *cmd1;
	const char *cmd2;
	const char *object_id;
	char formatter_type[64];
	const char *regex;

	struct ast_sip_cli_context context = {
		.indent_level = 0,
		.show_details = 0,
		.show_details_only_level_0 = 0,
		.recurse = 0,
	};

	if (cmd == CLI_INIT) {
		return NULL;
	}

	cmd1 = e->cmda[1];
	cmd2 = e->cmda[2];
	object_id = a->argv[3];

	if (!ast_ends_with(cmd2, "s")) {
		ast_copy_string(formatter_type, cmd2, sizeof(formatter_type));
		is_container = 0;
	} else if (ast_ends_with(cmd2, "ies")) {
		/* Take the plural "ies" off of the object name and re[place with "y". */
		int l = strlen(cmd2);
		snprintf(formatter_type, 64, "%*.*sy", l - 3, l - 3, cmd2);
		is_container = 1;
	} else {
		/* Take the plural "s" off of the object name. */
		ast_copy_string(formatter_type, cmd2, strlen(cmd2));
		is_container = 1;
	}

	if (!strcmp(cmd1, "show")) {
		context.show_details_only_level_0 = !is_container;
		context.recurse = 1;
	} else {
		is_container = 1;
	}

	if (cmd != CLI_GENERATE
		&& is_container
		&& a->argc >= 4
		&& strcmp(object_id, "like") == 0) {
		if (ast_strlen_zero(a->argv[4])) {
			return CLI_SHOWUSAGE;
		}
		regex = a->argv[4];
	} else {
		regex = "";
	}

	if (cmd == CLI_GENERATE
		&& (is_container
			|| a->argc > 4
			|| (a->argc == 4 && ast_strlen_zero(a->word)))) {
		return CLI_SUCCESS;
	}

	context.output_buffer = ast_str_create(256);
	if (!context.output_buffer) {
		return CLI_FAILURE;
	}

	formatter_entry = ast_sip_lookup_cli_formatter(formatter_type);
	if (!formatter_entry) {
		ast_log(LOG_ERROR, "No formatter registered for object type %s.\n",
			formatter_type);
		ast_free(context.output_buffer);
		return CLI_FAILURE;
	}
	ast_str_append(&context.output_buffer, 0, "\n");
	formatter_entry->print_header(NULL, &context, 0);
	ast_str_append(&context.output_buffer, 0,
		"==========================================================================================\n\n");

	if (is_container || cmd == CLI_GENERATE) {
		container = formatter_entry->get_container(regex);
		if (!container) {
			ast_cli(a->fd, "No container returned for object type %s.\n",
				formatter_type);
			ast_free(context.output_buffer);
			return CLI_FAILURE;
		}
	}

	if (cmd == CLI_GENERATE) {
		ast_free(context.output_buffer);
		return complete_show_sorcery_object(container, formatter_entry, a->word, a->n);
	}

	if (is_container) {
		if (!ao2_container_count(container)) {
			ast_free(context.output_buffer);
			ast_cli(a->fd, "No objects found.\n\n");
			return CLI_SUCCESS;
		}
		ao2_callback(container, OBJ_NODATA, formatter_entry->print_body, &context);
		ast_str_append(&context.output_buffer, 0, "\nObjects found: %d\n", ao2_container_count(container));

	} else {
		if (ast_strlen_zero(object_id)) {
			ast_free(context.output_buffer);
			ast_cli(a->fd, "No object specified.\n");
			return CLI_FAILURE;
		}

		object = formatter_entry->retrieve_by_id(object_id);
		if (!object) {
			ast_free(context.output_buffer);
			ast_cli(a->fd, "Unable to find object %s.\n\n", object_id);
			return CLI_SUCCESS;
		}
		formatter_entry->print_body(object, &context, 0);
	}

	ast_str_append(&context.output_buffer, 0, "\n");
	dump_str_and_free(a->fd, context.output_buffer);
	return CLI_SUCCESS;
}

static int formatter_sort(const void *obj, const void *arg, int flags)
{
	const struct ast_sip_cli_formatter_entry *left_obj = obj;
	const struct ast_sip_cli_formatter_entry *right_obj = arg;
	const char *right_key = arg;
	int cmp = 0;

	switch (flags & OBJ_SEARCH_MASK) {
	case OBJ_SEARCH_OBJECT:
		right_key = right_obj->name;
		/* Fall through */
	case OBJ_SEARCH_KEY:
		cmp = strcmp(left_obj->name, right_key);
		break;
	case OBJ_SEARCH_PARTIAL_KEY:
		cmp = strncmp(left_obj->name, right_key, strlen(right_key));
		break;
	default:
		cmp = 0;
		break;
	}

	return cmp;
}

static int formatter_compare(void *obj, void *arg, int flags)
{
	const struct ast_sip_cli_formatter_entry *left_obj = obj;
	const struct ast_sip_cli_formatter_entry *right_obj = arg;
	const char *right_key = arg;
	int cmp = 0;

	switch (flags & OBJ_SEARCH_MASK) {
	case OBJ_SEARCH_OBJECT:
		right_key = right_obj->name;
		/* Fall through */
	case OBJ_SEARCH_KEY:
		if (strcmp(left_obj->name, right_key) == 0) {;
			cmp = CMP_MATCH | CMP_STOP;
		}
		break;
	case OBJ_SEARCH_PARTIAL_KEY:
		if (strncmp(left_obj->name, right_key, strlen(right_key)) == 0) {
			cmp = CMP_MATCH;
		}
		break;
	default:
		cmp = 0;
		break;
	}

	return cmp;
}

static int formatter_hash(const void *obj, int flags)
{
	const struct ast_sip_cli_formatter_entry *left_obj = obj;
	if (flags & OBJ_SEARCH_OBJECT) {
		return ast_str_hash(left_obj->name);
	} else if (flags & OBJ_SEARCH_KEY) {
		return ast_str_hash(obj);
	}

	return -1;
}

struct ast_sip_cli_formatter_entry *ast_sip_lookup_cli_formatter(const char *name)
{
	return ao2_find(formatter_registry, name, OBJ_SEARCH_KEY | OBJ_NOLOCK);
}

int ast_sip_register_cli_formatter(struct ast_sip_cli_formatter_entry *formatter)
{
	ast_assert(formatter != NULL);
	ast_assert(formatter->name != NULL);
	ast_assert(formatter->print_body != NULL);
	ast_assert(formatter->print_header != NULL);
	ast_assert(formatter->get_container != NULL);
	ast_assert(formatter->iterate != NULL);
	ast_assert(formatter->get_id != NULL);
	ast_assert(formatter->retrieve_by_id != NULL);

	ao2_link(formatter_registry, formatter);

	return 0;
}
Example #5
0
/*! \brief
 * Open the local video source and allocate a buffer
 * for storing the image.
 */
static void *grab_v4l1_open(const char *dev, struct fbuf_t *geom, int fps)
{
	struct video_window vw = { 0 };	/* camera attributes */
	struct video_picture vp;
	int fd, i;
	struct grab_v4l1_desc *v;
	struct fbuf_t *b;

	/* name should be something under /dev/ */
	if (strncmp(dev, "/dev/", 5)) 
		return NULL;
	fd = open(dev, O_RDONLY | O_NONBLOCK);
	if (fd < 0) {
		ast_log(LOG_WARNING, "error opening camera %s\n", dev);
		return NULL;
	}

	v = ast_calloc(1, sizeof(*v));
	if (v == NULL) {
		ast_log(LOG_WARNING, "no memory for camera %s\n", dev);
		close(fd);
		return NULL;	/* no memory */
	}
	v->fd = fd;
	v->b = *geom;
	b = &v->b;	/* shorthand */

	i = fcntl(fd, F_GETFL);
	if (-1 == fcntl(fd, F_SETFL, i | O_NONBLOCK)) {
		/* non fatal, just emit a warning */
		ast_log(LOG_WARNING, "error F_SETFL for %s [%s]\n",
			dev, strerror(errno));
	}
	/* set format for the camera.
	 * In principle we could retry with a different format if the
	 * one we are asking for is not supported.
	 */
	vw.width = b->w;
	vw.height = b->h;
	vw.flags = fps << 16;
	if (ioctl(fd, VIDIOCSWIN, &vw) == -1) {
		ast_log(LOG_WARNING, "error setting format for %s [%s]\n",
			dev, strerror(errno));
		goto error;
	}
	if (ioctl(fd, VIDIOCGPICT, &vp) == -1) {
		ast_log(LOG_WARNING, "error reading picture info\n");
		goto error;
	}
	ast_log(LOG_WARNING,
		"contrast %d bright %d colour %d hue %d white %d palette %d\n",
		vp.contrast, vp.brightness,
		vp.colour, vp.hue,
		vp.whiteness, vp.palette);
	/* set the video format. Here again, we don't necessary have to
	 * fail if the required format is not supported, but try to use
	 * what the camera gives us.
	 */
	b->pix_fmt = vp.palette;
	vp.palette = VIDEO_PALETTE_YUV420P;
	if (ioctl(v->fd, VIDIOCSPICT, &vp) == -1) {
		ast_log(LOG_WARNING, "error setting palette, using %d\n",
			b->pix_fmt);
	} else
		b->pix_fmt = vp.palette;
	/* allocate the source buffer.
	 * XXX, the code here only handles yuv411, for other formats
	 * we need to look at pix_fmt and set size accordingly
	 */
	b->size = (b->w * b->h * 3)/2;	/* yuv411 */
	ast_log(LOG_WARNING, "videodev %s opened, size %dx%d %d\n",
		dev, b->w, b->h, b->size);
	b->data = ast_calloc(1, b->size);
	if (!b->data) {
		ast_log(LOG_WARNING, "error allocating buffer %d bytes\n",
			b->size);
		goto error;
	}
	ast_log(LOG_WARNING, "success opening camera\n");
	return v;

error:
	close(v->fd);
	fbuf_free(b);
	ast_free(v);
	return NULL;
}
/*! \internal
 * \brief Interval hook. Pulls a parked call from the parking bridge after the timeout is passed and sets the resolution to timeout.
 *
 * \param bridge_channel bridge channel this interval hook is being executed on
 * \param hook_pvt A pointer to the parked_user struct associated with the channel is stuffed in here
 */
static int parking_duration_callback(struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
	struct parked_user *user = hook_pvt;
	struct ast_channel *chan = user->chan;
	struct ast_context *park_dial_context;
	const char *dial_string;
	char *dial_string_flat;
	char parking_space[AST_MAX_EXTENSION];

	char returnexten[AST_MAX_EXTENSION];
	char *duplicate_returnexten;
	struct ast_exten *existing_exten;
	struct pbx_find_info pbx_finder = { .stacklen = 0 }; /* The rest is reset in pbx_find_extension */


	/* We are still in the bridge, so it's possible for other stuff to mess with the parked call before we leave the bridge
	   to deal with this, lock the parked user, check and set resolution. */
	ao2_lock(user);
	if (user->resolution != PARK_UNSET) {
		/* Abandon timeout since something else has resolved the parked user before we got to it. */
		ao2_unlock(user);
		return -1;
	}
	user->resolution = PARK_TIMEOUT;
	ao2_unlock(user);

	ast_bridge_channel_leave_bridge(bridge_channel, BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE,
		AST_CAUSE_NORMAL_CLEARING);

	dial_string = user->parker_dial_string;
	dial_string_flat = ast_strdupa(dial_string);
	flatten_dial_string(dial_string_flat);

	/* Set parking timeout channel variables */
	snprintf(parking_space, sizeof(parking_space), "%d", user->parking_space);
	ast_channel_lock(chan);
	ast_channel_stage_snapshot(chan);
	pbx_builtin_setvar_helper(chan, "PARKING_SPACE", parking_space);
	pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parking_space); /* Deprecated version of PARKING_SPACE */
	pbx_builtin_setvar_helper(chan, "PARKEDLOT", user->lot->name);
	pbx_builtin_setvar_helper(chan, "PARKER", dial_string);
	pbx_builtin_setvar_helper(chan, "PARKER_FLAT", dial_string_flat);
	parking_timeout_set_caller_features(chan, user->lot->cfg);
	ast_channel_stage_snapshot_done(chan);
	ast_channel_unlock(chan);

	/* Dialplan generation for park-dial extensions */

	if (ast_wrlock_contexts()) {
		ast_log(LOG_ERROR, "Failed to lock the contexts list. Can't add the park-dial extension.\n");
		return -1;
	}

	if (!(park_dial_context = ast_context_find_or_create(NULL, NULL, PARK_DIAL_CONTEXT, BASE_REGISTRAR))) {
		ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", PARK_DIAL_CONTEXT);
		if (ast_unlock_contexts()) {
			ast_assert(0);
		}
		goto abandon_extension_creation;
	}

	if (ast_wrlock_context(park_dial_context)) {
		ast_log(LOG_ERROR, "failed to obtain write lock on context '%s'\n", PARK_DIAL_CONTEXT);
		if (ast_unlock_contexts()) {
			ast_assert(0);
		}
		goto abandon_extension_creation;
	}

	if (ast_unlock_contexts()) {
		ast_assert(0);
	}

	snprintf(returnexten, sizeof(returnexten), "%s,%u", dial_string,
		user->lot->cfg->comebackdialtime);

	duplicate_returnexten = ast_strdup(returnexten);
	if (!duplicate_returnexten) {
		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
	}

	/* If an extension already exists here because we registered it for another parked call timing out, then we may overwrite it. */
	if ((existing_exten = pbx_find_extension(NULL, NULL, &pbx_finder, PARK_DIAL_CONTEXT, dial_string_flat, 1, NULL, NULL, E_MATCH)) &&
	    (strcmp(ast_get_extension_registrar(existing_exten), BASE_REGISTRAR))) {
		ast_debug(3, "An extension for '%s@%s' was already registered by another registrar '%s'\n",
			dial_string_flat, PARK_DIAL_CONTEXT, ast_get_extension_registrar(existing_exten));
	} else if (ast_add_extension2_nolock(park_dial_context, 1, dial_string_flat, 1, NULL, NULL,
			"Dial", duplicate_returnexten, ast_free_ptr, BASE_REGISTRAR)) {
			ast_free(duplicate_returnexten);
		ast_log(LOG_ERROR, "Failed to create parking redial parker extension %s@%s - Dial(%s)\n",
			dial_string_flat, PARK_DIAL_CONTEXT, returnexten);
	}

	if (ast_unlock_context(park_dial_context)) {
		ast_assert(0);
	}

abandon_extension_creation:

	/* async_goto the proper PBX destination - this should happen when we come out of the bridge */
	if (!ast_strlen_zero(user->comeback)) {
		ast_async_parseable_goto(chan, user->comeback);
	} else {
		comeback_goto(user, user->lot);
	}

	return -1;
}

void say_parking_space(struct ast_bridge_channel *bridge_channel, const char *payload)
{
	unsigned int numeric_value;
	unsigned int hangup_after;

	if (sscanf(payload, "%u %u", &hangup_after, &numeric_value) != 2) {
		/* If say_parking_space is called with a non-numeric string, we have a problem. */
		ast_assert(0);
		ast_bridge_channel_leave_bridge(bridge_channel,
			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
		return;
	}

	ast_say_digits(bridge_channel->chan, numeric_value, "",
		ast_channel_language(bridge_channel->chan));

	if (hangup_after) {
		ast_bridge_channel_leave_bridge(bridge_channel,
			BRIDGE_CHANNEL_STATE_END_NO_DISSOLVE, AST_CAUSE_NORMAL_CLEARING);
	}
}
Example #7
0
static int odbc_load_module(int reload)
{
	int res = 0;
	struct ast_config *cfg;
	struct ast_variable *var;
	const char *tmp;
	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

	do {
		cfg = ast_config_load(config_file, config_flags);
		if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
			ast_log(LOG_WARNING, "cdr_odbc: Unable to load config for ODBC CDR's: %s\n", config_file);
			res = AST_MODULE_LOAD_DECLINE;
			break;
		} else if (cfg == CONFIG_STATUS_FILEUNCHANGED)
			break;

		var = ast_variable_browse(cfg, "global");
		if (!var) {
			/* nothing configured */
			break;
		}

		if ((tmp = ast_variable_retrieve(cfg, "global", "dsn")) == NULL) {
			ast_log(LOG_WARNING, "cdr_odbc: dsn not specified.  Assuming asteriskdb\n");
			tmp = "asteriskdb";
		}
		if (dsn)
			ast_free(dsn);
		dsn = ast_strdup(tmp);
		if (dsn == NULL) {
			res = -1;
			break;
		}

		if (((tmp = ast_variable_retrieve(cfg, "global", "dispositionstring"))) && ast_true(tmp))
			ast_set_flag(&config, CONFIG_DISPOSITIONSTRING);
		else
			ast_clear_flag(&config, CONFIG_DISPOSITIONSTRING);

		if (((tmp = ast_variable_retrieve(cfg, "global", "loguniqueid"))) && ast_true(tmp)) {
			ast_set_flag(&config, CONFIG_LOGUNIQUEID);
			ast_debug(1, "cdr_odbc: Logging uniqueid\n");
		} else {
			ast_clear_flag(&config, CONFIG_LOGUNIQUEID);
			ast_debug(1, "cdr_odbc: Not logging uniqueid\n");
		}

		if (((tmp = ast_variable_retrieve(cfg, "global", "usegmtime"))) && ast_true(tmp)) {
			ast_set_flag(&config, CONFIG_USEGMTIME);
			ast_debug(1, "cdr_odbc: Logging in GMT\n");
		} else {
			ast_clear_flag(&config, CONFIG_USEGMTIME);
			ast_debug(1, "cdr_odbc: Logging in local time\n");
		}

		if (((tmp = ast_variable_retrieve(cfg, "global", "hrtime"))) && ast_true(tmp)) {
			ast_set_flag(&config, CONFIG_HRTIME);
			ast_debug(1, "cdr_odbc: Logging billsec and duration fields as floats\n");
		} else {
			ast_clear_flag(&config, CONFIG_HRTIME);
			ast_debug(1, "cdr_odbc: Logging billsec and duration fields as integers\n");
		}

		if ((tmp = ast_variable_retrieve(cfg, "global", "table")) == NULL) {
			ast_log(LOG_WARNING, "cdr_odbc: table not specified.  Assuming cdr\n");
			tmp = "cdr";
		}
		if (table)
			ast_free(table);
		table = ast_strdup(tmp);
		if (table == NULL) {
			res = -1;
			break;
		}

		if (!ast_test_flag(&config, CONFIG_REGISTERED)) {
			res = ast_cdr_register(name, ast_module_info->description, odbc_log);
			if (res) {
				ast_log(LOG_ERROR, "cdr_odbc: Unable to register ODBC CDR handling\n");
			} else {
				ast_set_flag(&config, CONFIG_REGISTERED);
			}
		}
	} while (0);

	if (ast_test_flag(&config, CONFIG_REGISTERED) && (!cfg || dsn == NULL || table == NULL)) {
		ast_cdr_backend_suspend(name);
		ast_clear_flag(&config, CONFIG_REGISTERED);
	} else {
		ast_cdr_backend_unsuspend(name);
	}

	if (cfg && cfg != CONFIG_STATUS_FILEUNCHANGED && cfg != CONFIG_STATUS_FILEINVALID) {
		ast_config_destroy(cfg);
	}
	return res;
}
Example #8
0
/*! \brief Free a \ref json_mem block. */
static void json_mem_free(struct json_mem *mem)
{
	mem->magic = 0;
	ast_mutex_destroy(&mem->mutex);
	ast_free(mem);
}
Example #9
0
static void datastore_destroy_cb(void *data) {
	ast_free(data);
	ast_debug(1, "JITTERBUFFER datastore destroyed\n");
}
Example #10
0
/*! 
 * \brief Stop monitoring channel 
 * \param chan 
 * \param need_lock
 * Stop the recording, close any open streams, mix in/out channels if required
 * \return Always 0
*/
int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
{
	int delfiles = 0;

	LOCK_IF_NEEDED(chan, need_lock);

	if (chan->monitor) {
		char filename[ FILENAME_MAX ];

		if (chan->monitor->read_stream) {
			ast_closestream(chan->monitor->read_stream);
		}
		if (chan->monitor->write_stream) {
			ast_closestream(chan->monitor->write_stream);
		}

		if (chan->monitor->filename_changed && !ast_strlen_zero(chan->monitor->filename_base)) {
			if (ast_fileexists(chan->monitor->read_filename,NULL,NULL) > 0) {
				snprintf(filename, FILENAME_MAX, "%s-in", chan->monitor->filename_base);
				if (ast_fileexists(filename, NULL, NULL) > 0) {
					ast_filedelete(filename, NULL);
				}
				ast_filerename(chan->monitor->read_filename, filename, chan->monitor->format);
			} else {
				ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->read_filename);
			}

			if (ast_fileexists(chan->monitor->write_filename,NULL,NULL) > 0) {
				snprintf(filename, FILENAME_MAX, "%s-out", chan->monitor->filename_base);
				if (ast_fileexists(filename, NULL, NULL) > 0) {
					ast_filedelete(filename, NULL);
				}
				ast_filerename(chan->monitor->write_filename, filename, chan->monitor->format);
			} else {
				ast_log(LOG_WARNING, "File %s not found\n", chan->monitor->write_filename);
			}
		}

		if (chan->monitor->joinfiles && !ast_strlen_zero(chan->monitor->filename_base)) {
			char tmp[1024];
			char tmp2[1024];
			const char *format = !strcasecmp(chan->monitor->format,"wav49") ? "WAV" : chan->monitor->format;
			char *fname_base = chan->monitor->filename_base;
			const char *execute, *execute_args;
			/* at this point, fname_base really is the full path */

			/* Set the execute application */
			execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
			if (ast_strlen_zero(execute)) {
#ifdef HAVE_SOXMIX
				execute = "nice -n 19 soxmix";
#else
				execute = "nice -n 19 sox -m";
#endif
				format = get_soxmix_format(format);
				delfiles = 1;
			} 
			execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
			if (ast_strlen_zero(execute_args)) {
				execute_args = "";
			}
			
			snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
				execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
			if (delfiles) {
				snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
				ast_copy_string(tmp, tmp2, sizeof(tmp));
			}
			ast_debug(1,"monitor executing %s\n",tmp);
			if (ast_safe_system(tmp) == -1)
				ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
		}
		
		ast_free(chan->monitor->format);
		ast_free(chan->monitor);
		chan->monitor = NULL;

		ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStop",
			                "Channel: %s\r\n"
	                        "Uniqueid: %s\r\n",
	                        chan->name,
	                        chan->uniqueid
	                        );
		pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
	}
	pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);

	UNLOCK_IF_NEEDED(chan, need_lock);

	return 0;
}
Example #11
0
static int speex_write(struct ast_channel *chan, const char *cmd, char *data, const char *value)
{
	struct ast_datastore *datastore = NULL;
	struct speex_info *si = NULL;
	struct speex_direction_info **sdi = NULL;
	int is_new = 0;

	if (strcasecmp(data, "rx") && strcasecmp(data, "tx")) {
		ast_log(LOG_ERROR, "Invalid argument provided to the %s function\n", cmd);
		return -1;
	}

	ast_channel_lock(chan);
	if (!(datastore = ast_channel_datastore_find(chan, &speex_datastore, NULL))) {
		ast_channel_unlock(chan);

		if (!(datastore = ast_datastore_alloc(&speex_datastore, NULL))) {
			return 0;
		}

		if (!(si = ast_calloc(1, sizeof(*si)))) {
			ast_datastore_free(datastore);
			return 0;
		}

		ast_audiohook_init(&si->audiohook, AST_AUDIOHOOK_TYPE_MANIPULATE, "speex", AST_AUDIOHOOK_MANIPULATE_ALL_RATES);
		si->audiohook.manipulate_callback = speex_callback;
		si->lastrate = 8000;
		is_new = 1;
	} else {
		ast_channel_unlock(chan);
		si = datastore->data;
	}

	if (!strcasecmp(data, "rx")) {
		sdi = &si->rx;
	} else {
		sdi = &si->tx;
	}

	if (!*sdi) {
		if (!(*sdi = ast_calloc(1, sizeof(**sdi)))) {
			return 0;
		}
		/* Right now, the audiohooks API will _only_ provide us 8 kHz slinear
		 * audio.  When it supports 16 kHz (or any other sample rates, we will
		 * have to take that into account here. */
		(*sdi)->samples = -1;
	}

	if (!strcasecmp(cmd, "agc")) {
		if (!sscanf(value, "%30f", &(*sdi)->agclevel))
			(*sdi)->agclevel = ast_true(value) ? DEFAULT_AGC_LEVEL : 0.0;
	
		if ((*sdi)->agclevel > 32768.0) {
			ast_log(LOG_WARNING, "AGC(%s)=%.01f is greater than 32768... setting to 32768 instead\n", 
					((*sdi == si->rx) ? "rx" : "tx"), (*sdi)->agclevel);
			(*sdi)->agclevel = 32768.0;
		}
	
		(*sdi)->agc = !!((*sdi)->agclevel);

		if ((*sdi)->state) {
			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC, &(*sdi)->agc);
			if ((*sdi)->agc) {
				speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_AGC_LEVEL, &(*sdi)->agclevel);
			}
		}
	} else if (!strcasecmp(cmd, "denoise")) {
		(*sdi)->denoise = (ast_true(value) != 0);

		if ((*sdi)->state) {
			speex_preprocess_ctl((*sdi)->state, SPEEX_PREPROCESS_SET_DENOISE, &(*sdi)->denoise);
		}
	}

	if (!(*sdi)->agc && !(*sdi)->denoise) {
		if ((*sdi)->state)
			speex_preprocess_state_destroy((*sdi)->state);

		ast_free(*sdi);
		*sdi = NULL;
	}

	if (!si->rx && !si->tx) {
		if (is_new) {
			is_new = 0;
		} else {
			ast_channel_lock(chan);
			ast_channel_datastore_remove(chan, datastore);
			ast_channel_unlock(chan);
			ast_audiohook_remove(chan, &si->audiohook);
			ast_audiohook_detach(&si->audiohook);
		}
		
		ast_datastore_free(datastore);
	}

	if (is_new) { 
		datastore->data = si;
		ast_channel_lock(chan);
		ast_channel_datastore_add(chan, datastore);
		ast_channel_unlock(chan);
		ast_audiohook_attach(chan, &si->audiohook);
	}

	return 0;
}
Example #12
0
/*! \brief Start monitoring a channel
 * \param chan ast_channel struct to record
 * \param format_spec file format to use for recording
 * \param fname_base filename base to record to
 * \param need_lock whether to lock the channel mutex
 * \param stream_action whether to record the input and/or output streams.  X_REC_IN | X_REC_OUT is most often used
 * Creates the file to record, if no format is specified it assumes WAV
 * It also sets channel variable __MONITORED=yes
 * \retval 0 on success
 * \retval -1 on failure
 */
int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
					     const char *fname_base, int need_lock, int stream_action)
{
	int res = 0;

	LOCK_IF_NEEDED(chan, need_lock);

	if (!(chan->monitor)) {
		struct ast_channel_monitor *monitor;
		char *channel_name, *p;

		/* Create monitoring directory if needed */
		ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);

		if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
			UNLOCK_IF_NEEDED(chan, need_lock);
			return -1;
		}

		/* Determine file names */
		if (!ast_strlen_zero(fname_base)) {
			int directory = strchr(fname_base, '/') ? 1 : 0;
			const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
			const char *absolute_suffix = *fname_base == '/' ? "" : "/";

			snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
					 	absolute, absolute_suffix, fname_base);

			/* try creating the directory just in case it doesn't exist */
			if (directory) {
				char *name = ast_strdupa(monitor->filename_base);
				ast_mkdir(dirname(name), 0777);
			}
		} else {
			ast_mutex_lock(&monitorlock);
			snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%ld",
						ast_config_AST_MONITOR_DIR, seq);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%ld",
						ast_config_AST_MONITOR_DIR, seq);
			seq++;
			ast_mutex_unlock(&monitorlock);

			channel_name = ast_strdupa(chan->name);
			while ((p = strchr(channel_name, '/'))) {
				*p = '-';
			}
			snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
					 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
			monitor->filename_changed = 1;
		}

		monitor->stop = ast_monitor_stop;

		/* Determine file format */
		if (!ast_strlen_zero(format_spec)) {
			monitor->format = ast_strdup(format_spec);
		} else {
			monitor->format = ast_strdup("wav");
		}
		
		/* open files */
		if (stream_action & X_REC_IN) {
			if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
				ast_filedelete(monitor->read_filename, NULL);
			if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->read_filename);
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->read_stream = NULL;

		if (stream_action & X_REC_OUT) {
			if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
				ast_filedelete(monitor->write_filename, NULL);
			}
			if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->write_filename);
				ast_closestream(monitor->read_stream);
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->write_stream = NULL;

		chan->monitor = monitor;
		ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
		/* so we know this call has been monitored in case we need to bill for it or something */
		pbx_builtin_setvar_helper(chan, "__MONITORED","true");

		ast_manager_event(chan, EVENT_FLAG_CALL, "MonitorStart",
			                "Channel: %s\r\n"
					        "Uniqueid: %s\r\n",
	                        chan->name,
			                chan->uniqueid);
	} else {
		ast_debug(1,"Cannot start monitoring %s, already monitored\n", chan->name);
		res = -1;
	}

	UNLOCK_IF_NEEDED(chan, need_lock);

	return res;
}
static void celt_destroy(struct ast_format *format)
{
	struct celt_attr *attr = ast_format_get_attribute_data(format);

	ast_free(attr);
}
Example #14
0
static void qualify_data_destroy(struct qualify_data *qual_data)
{
	ao2_cleanup(qual_data->endpoint);
	ast_free(qual_data);
}
/*! 
 * \brief Stop monitoring channel 
 * \param chan 
 * \param need_lock
 * Stop the recording, close any open streams, mix in/out channels if required
 * \return Always 0
*/
int AST_OPTIONAL_API_NAME(ast_monitor_stop)(struct ast_channel *chan, int need_lock)
{
	int delfiles = 0;
	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);

	LOCK_IF_NEEDED(chan, need_lock);

	if (ast_channel_monitor(chan)) {
		char filename[ FILENAME_MAX ];

		if (ast_channel_monitor(chan)->read_stream) {
			ast_closestream(ast_channel_monitor(chan)->read_stream);
		}
		if (ast_channel_monitor(chan)->write_stream) {
			ast_closestream(ast_channel_monitor(chan)->write_stream);
		}

		if (ast_channel_monitor(chan)->filename_changed && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
			if (ast_fileexists(ast_channel_monitor(chan)->read_filename,NULL,NULL) > 0) {
				snprintf(filename, FILENAME_MAX, "%s-in", ast_channel_monitor(chan)->filename_base);
				if (ast_fileexists(filename, NULL, NULL) > 0) {
					ast_filedelete(filename, NULL);
				}
				ast_filerename(ast_channel_monitor(chan)->read_filename, filename, ast_channel_monitor(chan)->format);
			} else {
				ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->read_filename);
			}

			if (ast_fileexists(ast_channel_monitor(chan)->write_filename,NULL,NULL) > 0) {
				snprintf(filename, FILENAME_MAX, "%s-out", ast_channel_monitor(chan)->filename_base);
				if (ast_fileexists(filename, NULL, NULL) > 0) {
					ast_filedelete(filename, NULL);
				}
				ast_filerename(ast_channel_monitor(chan)->write_filename, filename, ast_channel_monitor(chan)->format);
			} else {
				ast_log(LOG_WARNING, "File %s not found\n", ast_channel_monitor(chan)->write_filename);
			}
		}

		if (ast_channel_monitor(chan)->joinfiles && !ast_strlen_zero(ast_channel_monitor(chan)->filename_base)) {
			char tmp[1024];
			char tmp2[1024];
			const char *format = !strcasecmp(ast_channel_monitor(chan)->format,"wav49") ? "WAV" : ast_channel_monitor(chan)->format;
			char *fname_base = ast_channel_monitor(chan)->filename_base;
			const char *execute, *execute_args;
			/* at this point, fname_base really is the full path */

			/* Set the execute application */
			execute = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC");
			if (ast_strlen_zero(execute)) {
#ifdef HAVE_SOXMIX
				execute = "nice -n 19 soxmix";
#else
				execute = "nice -n 19 sox -m";
#endif
				format = get_soxmix_format(format);
				delfiles = 1;
			} 
			execute_args = pbx_builtin_getvar_helper(chan, "MONITOR_EXEC_ARGS");
			if (ast_strlen_zero(execute_args)) {
				execute_args = "";
			}
			
			snprintf(tmp, sizeof(tmp), "%s \"%s-in.%s\" \"%s-out.%s\" \"%s.%s\" %s &",
				execute, fname_base, format, fname_base, format, fname_base, format,execute_args);
			if (delfiles) {
				snprintf(tmp2,sizeof(tmp2), "( %s& rm -f \"%s-\"* ) &",tmp, fname_base); /* remove legs when done mixing */
				ast_copy_string(tmp, tmp2, sizeof(tmp));
			}
			ast_debug(1,"monitor executing %s\n",tmp);
			if (ast_safe_system(tmp) == -1)
				ast_log(LOG_WARNING, "Execute of %s failed.\n",tmp);
		}

		if (!ast_strlen_zero(ast_channel_monitor(chan)->beep_id)) {
			ast_beep_stop(chan, ast_channel_monitor(chan)->beep_id);
		}

		ast_free(ast_channel_monitor(chan)->format);
		ast_free(ast_channel_monitor(chan));
		ast_channel_monitor_set(chan, NULL);

		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
				ast_channel_monitor_stop_type(),
				NULL);
		if (message) {
			stasis_publish(ast_channel_topic(chan), message);
		}
		pbx_builtin_setvar_helper(chan, "MONITORED", NULL);
	}
	pbx_builtin_setvar_helper(chan, "AUTO_MONITOR", NULL);

	UNLOCK_IF_NEEDED(chan, need_lock);

	return 0;
}
Example #16
0
/***********************************************************************
 * Main program for the Compiler
 **********************************************************************/
int main (int argc, char *argv[]) {
  getOpts (argc, argv); /* Set up and apply command line options */

/***********************************************************************
 * Compiler Initialization.
 *
 * If explicit initialization of any phase of the compilation is needed,
 * calls to initialization routines in the applicable modules are placed
 * here.
 **********************************************************************/
  errorOccurred = FALSE;

/***********************************************************************
 * Start the Compilation
 **********************************************************************/
  if (dumpSource)
    sourceDump();

/* Phase 1: Scanner. In phase 2 and after the following code should be
 * removed */
/*
  while (yylex())
    if (errorOccurred)
      break;
 */

/* Phase 2: Parser -- should allocate an AST, storing the reference in the
 * global variable "ast", and build the AST there. */
  if(1 == yyparse()) {
    return 0; // parse failed
  }

  build_table(ast);
  insert_predef();
  //display();

  if(semantic_check(ast)==-1){
	  //printf();
	  fprintf(stderr, "SYMANTIC CHECK FAILED\n");
  }

/* Phase 3: Call the AST dumping routine if requested */
  if (dumpAST)
    ast_print(ast);
/* Phase 4: Add code to call the code generation routine */
/* TODO: call your code generation routine here */
  if (errorOccurred)
    fprintf(outputFile,"Failed to compile\n");
  else 
   // genCode(ast);
    ;
/***********************************************************************
 * Post Compilation Cleanup
 **********************************************************************/

/* Make calls to any cleanup or finalization routines here. */
  ast_free(ast);

  /* Clean up files if necessary */
  if (inputFile != DEFAULT_INPUT_FILE)
    fclose (inputFile);
  if (errorFile != DEFAULT_ERROR_FILE)
    fclose (errorFile);
  if (dumpFile != DEFAULT_DUMP_FILE)
    fclose (dumpFile);
  if (traceFile != DEFAULT_TRACE_FILE)
    fclose (traceFile);
  if (outputFile != DEFAULT_OUTPUT_FILE)
    fclose (outputFile);
  if (runInputFile != DEFAULT_RUN_INPUT_FILE)
    fclose (runInputFile);

  return 0;
}
Example #17
0
static void send_unsolicited_mwi_notify(struct mwi_subscription *sub,
		struct ast_sip_message_accumulator *counter)
{
	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
				"endpoint", sub->id), ao2_cleanup);
	char *endpoint_aors;
	char *aor_name;
	struct ast_sip_body body;
	struct ast_str *body_text;
	struct ast_sip_body_data body_data = {
		.body_type = AST_SIP_MESSAGE_ACCUMULATOR,
		.body_data = counter,
	};

	if (!endpoint) {
		ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because endpoint does not exist\n",
				sub->id);
		return;
	}
	if (ast_strlen_zero(endpoint->aors)) {
		ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because the endpoint has no"
				" configured AORs\n", sub->id);
		return;
	}

	body.type = MWI_TYPE;
	body.subtype = MWI_SUBTYPE;

	body_text = ast_str_create(64);

	if (!body_text) {
		return;
	}

	if (ast_sip_pubsub_generate_body_content(body.type, body.subtype, &body_data, &body_text)) {
		ast_log(LOG_WARNING, "Unable to generate SIP MWI NOTIFY body.\n");
		ast_free(body_text);
		return;
	}

	body.body_text = ast_str_buffer(body_text);

	endpoint_aors = ast_strdupa(endpoint->aors);

	ast_debug(5, "Sending unsolicited MWI NOTIFY to endpoint %s, new messages: %d, old messages: %d\n",
			sub->id, counter->new_msgs, counter->old_msgs);

	while ((aor_name = strsep(&endpoint_aors, ","))) {
		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
		struct unsolicited_mwi_data mwi_data = {
			.sub = sub,
			.endpoint = endpoint,
			.body = &body,
		};

		if (!aor) {
			ast_log(LOG_WARNING, "Unable to locate AOR %s for unsolicited MWI\n", aor_name);
			continue;
		}

		contacts = ast_sip_location_retrieve_aor_contacts(aor);
		if (!contacts || (ao2_container_count(contacts) == 0)) {
			ast_log(LOG_WARNING, "No contacts bound to AOR %s. Cannot send unsolicited MWI.\n", aor_name);
			continue;
		}

		ao2_callback(contacts, OBJ_NODATA, send_unsolicited_mwi_notify_to_contact, &mwi_data);
	}

	ast_free(body_text);
}
Example #18
0
static void datastore_destroy_cb(void *data) {
	ast_free(data);
}
Example #19
0
static void sorcery_astdb_close(void *data)
{
	ast_free(data);
}
Example #20
0
static void hook_destroy_cb(void *framedata)
{
	ast_free(framedata);
}
Example #21
0
static void dump_str_and_free(int fd, struct ast_str *buf)
{
	ast_cli(fd, "%s", ast_str_buffer(buf));
	ast_free(buf);
}
Example #22
0
/*! /brief Free test element */
static void ht_delete(void *obj)
{
	ast_free(obj);
}
Example #23
0
/* ENUM lookup */
int ast_get_enum(struct ast_channel *chan, const char *number, char *dst, int dstlen, char *tech, int techlen, char* suffix, char* options, unsigned int record, struct enum_context **argcontext)
{
    struct enum_context *context;
    char tmp[512];
    char domain[256];
    char left[128];
    char middle[128];
    char naptrinput[128];
    char apex[128] = "";
    int ret = -1;
    /* for ISN rewrite */
    char *p1 = NULL;
    char *p2 = NULL;
    char *p3 = NULL;
    int k = 0;
    int i = 0;
    int z = 0;
    int spaceleft = 0;
    struct timeval time_start, time_end;

    if (ast_strlen_zero(suffix)) {
        ast_log(LOG_WARNING, "ast_get_enum need a suffix parameter now.\n");
        return -1;
    }

    ast_debug(2, "num='%s', tech='%s', suffix='%s', options='%s', record=%u\n", number, tech, suffix, options, record);

    /*
      We don't need that any more, that "n" preceding the number has been replaced by a flag
      in the options paramter.
    	ast_copy_string(naptrinput, number, sizeof(naptrinput));
    */
    /*
     * The "number" parameter includes a leading '+' if it's a full E.164 number (and not ISN)
     * We need to preserve that as the regex inside NAPTRs expect the +.
     *
     * But for the domain generation, the '+' is a nuissance, so we get rid of it.
    */
    ast_copy_string(naptrinput, number[0] == 'n' ? number + 1 : number, sizeof(naptrinput));
    if (number[0] == '+') {
        number++;
    }

    if (!(context = ast_calloc(1, sizeof(*context)))) {
        return -1;
    }

    if ((p3 = strchr(naptrinput, '*'))) {
        *p3='\0';
    }

    context->naptrinput = naptrinput;	/* The number */
    context->dst = dst;			/* Return string */
    context->dstlen = dstlen;
    context->tech = tech;
    context->techlen = techlen;
    context->options = 0;
    context->position = record > 0 ? record : 1;
    context->count = 0;
    context->naptr_rrs = NULL;
    context->naptr_rrs_count = 0;

    /*
     * Process options:
     *
     *	c	Return count, not URI
     *	i	Use infrastructure ENUM
     *	s	Do ISN transformation
     *	d	Direct DNS query: no reversing.
     *
     */
    if (options != NULL) {
        if (strchr(options,'s')) {
            context->options |= ENUMLOOKUP_OPTIONS_ISN;
        } else if (strchr(options,'i')) {
            context->options |= ENUMLOOKUP_OPTIONS_IENUM;
        } else if (strchr(options,'d')) {
            context->options |= ENUMLOOKUP_OPTIONS_DIRECT;
        }
        if (strchr(options,'c')) {
            context->options |= ENUMLOOKUP_OPTIONS_COUNT;
        }
        if (strchr(number,'*')) {
            context->options |= ENUMLOOKUP_OPTIONS_ISN;
        }
    }
    ast_debug(2, "ENUM options(%s): pos=%d, options='%d'\n", options, context->position, context->options);
    ast_debug(1, "n='%s', tech='%s', suffix='%s', options='%d', record='%d'\n",
              number, tech, suffix, context->options, context->position);

    /*
     * This code does more than simple RFC3261 ENUM. All these rewriting
     * schemes have in common that they build the FQDN for the NAPTR lookup
     * by concatenating
     *    - a number which needs be flipped and "."-seperated 	(left)
     *    - some fixed string					(middle)
     *    - an Apex.						(apex)
     *
     * The RFC3261 ENUM is: left=full number, middle="", apex=from args.
     * ISN:  number = "middle*left", apex=from args
     * I-ENUM: EBL parameters build the split, can change apex
     * Direct: left="", middle=argument, apex=from args
     *
     */

    /* default: the whole number will be flipped, no middle domain component */
    ast_copy_string(left, number, sizeof(left));
    middle[0] = '\0';
    /*
     * I-ENUM can change the apex, thus we copy it
     */
    ast_copy_string(apex, suffix, sizeof(apex));
    /* ISN rewrite */
    if ((context->options & ENUMLOOKUP_OPTIONS_ISN) && (p1 = strchr(number, '*'))) {
        *p1++ = '\0';
        ast_copy_string(left, number, sizeof(left));
        ast_copy_string(middle, p1, sizeof(middle) - 1);
        strcat(middle, ".");
        ast_debug(2, "ISN ENUM: left=%s, middle='%s'\n", left, middle);
        /* Direct DNS lookup rewrite */
    } else if (context->options & ENUMLOOKUP_OPTIONS_DIRECT) {
        left[0] = 0; /* nothing to flip around */
        ast_copy_string(middle, number, sizeof(middle) - 1);
        strcat(middle, ".");
        ast_debug(2, "DIRECT ENUM:  middle='%s'\n", middle);
        /* Infrastructure ENUM rewrite */
    } else if (context->options & ENUMLOOKUP_OPTIONS_IENUM) {
        int sdl = 0;
        char cc[8];
        char sep[256], n_apex[256];
        int cc_len = cclen(number);
        sdl = cc_len;
        ast_mutex_lock(&enumlock);
        ast_copy_string(sep, ienum_branchlabel, sizeof(sep)); /* default */
        ast_mutex_unlock(&enumlock);

        switch (ebl_alg) {
        case ENUMLOOKUP_BLR_EBL:
            ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
            sdl = blr_ebl(cc, suffix, sep, sizeof(sep) - 1, n_apex, sizeof(n_apex) - 1);

            if (sdl >= 0) {
                ast_copy_string(apex, n_apex, sizeof(apex));
                ast_debug(2, "EBL ENUM: sep=%s, apex='%s'\n", sep, n_apex);
            } else {
                sdl = cc_len;
            }
            break;
        case ENUMLOOKUP_BLR_TXT:
            ast_copy_string(cc, number, cc_len); /* cclen() never returns more than 3 */
            sdl = blr_txt(cc, suffix);

            if (sdl < 0) {
                sdl = cc_len;
            }
            break;

        case ENUMLOOKUP_BLR_CC:	/* BLR is at the country-code level */
        default:
            sdl = cc_len;
            break;
        }

        if (sdl > strlen(number)) {	/* Number too short for this sdl? */
            ast_log(LOG_WARNING, "I-ENUM: subdomain location %d behind number %s\n", sdl, number);
            ast_free(context);
            return 0;
        }
        ast_copy_string(left, number + sdl, sizeof(left));

        ast_mutex_lock(&enumlock);
        ast_copy_string(middle, sep, sizeof(middle) - 1);
        strcat(middle, ".");
        ast_mutex_unlock(&enumlock);

        /* check the space we need for middle */
        if ((sdl * 2 + strlen(middle) + 2) > sizeof(middle)) {
            ast_log(LOG_WARNING, "ast_get_enum: not enough space for I-ENUM rewrite.\n");
            ast_free(context);
            return -1;
        }

        p1 = middle + strlen(middle);
        for (p2 = (char *) number + sdl - 1; p2 >= number; p2--) {
            if (isdigit(*p2)) {
                *p1++ = *p2;
                *p1++ = '.';
            }
        }
        *p1 = '\0';

        ast_debug(2, "I-ENUM: cclen=%d, left=%s, middle='%s', apex='%s'\n", cc_len, left, middle, apex);
    }

    if (strlen(left) * 2 + 2 > sizeof(domain)) {
        ast_log(LOG_WARNING, "string to long in ast_get_enum\n");
        ast_free(context);
        return -1;
    }

    /* flip left into domain */
    p1 = domain;
    for (p2 = left + strlen(left); p2 >= left; p2--) {
        if (isdigit(*p2)) {
            *p1++ = *p2;
            *p1++ = '.';
        }
    }
    *p1 = '\0';

    if (chan && ast_autoservice_start(chan) < 0) {
        ast_free(context);
        return -1;
    }

    spaceleft = sizeof(tmp) - 2;
    ast_copy_string(tmp, domain, spaceleft);
    spaceleft -= strlen(domain);

    if (*middle) {
        strncat(tmp, middle, spaceleft);
        spaceleft -= strlen(middle);
    }

    strncat(tmp,apex,spaceleft);
    time_start = ast_tvnow();
    ret = ast_search_dns(context, tmp, C_IN, T_NAPTR, enum_callback);
    time_end = ast_tvnow();

    ast_debug(2, "profiling: %s, %s, %" PRIi64 " ms\n",
              (ret == 0) ? "OK" : "FAIL", tmp, ast_tvdiff_ms(time_end, time_start));

    if (ret < 0) {
        ast_debug(1, "No such number found: %s (%s)\n", tmp, strerror(errno));
        context->naptr_rrs_count = -1;
        strcpy(dst, "0");
        ret = 0;
    }

    if (context->naptr_rrs_count >= context->position && ! (context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
        /* sort array by NAPTR order/preference */
        for (k = 0; k < context->naptr_rrs_count; k++) {
            for (i = 0; i < context->naptr_rrs_count; i++) {
                /* use order first and then preference to compare */
                if ((ntohs(context->naptr_rrs[k].naptr.order) < ntohs(context->naptr_rrs[i].naptr.order)
                        && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
                        || (ntohs(context->naptr_rrs[k].naptr.order) > ntohs(context->naptr_rrs[i].naptr.order)
                            && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
                    z = context->naptr_rrs[k].sort_pos;
                    context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
                    context->naptr_rrs[i].sort_pos = z;
                    continue;
                }
                if (ntohs(context->naptr_rrs[k].naptr.order) == ntohs(context->naptr_rrs[i].naptr.order)) {
                    if ((ntohs(context->naptr_rrs[k].naptr.pref) < ntohs(context->naptr_rrs[i].naptr.pref)
                            && context->naptr_rrs[k].sort_pos > context->naptr_rrs[i].sort_pos)
                            || (ntohs(context->naptr_rrs[k].naptr.pref) > ntohs(context->naptr_rrs[i].naptr.pref)
                                && context->naptr_rrs[k].sort_pos < context->naptr_rrs[i].sort_pos)) {
                        z = context->naptr_rrs[k].sort_pos;
                        context->naptr_rrs[k].sort_pos = context->naptr_rrs[i].sort_pos;
                        context->naptr_rrs[i].sort_pos = z;
                    }
                }
            }
        }
        for (k = 0; k < context->naptr_rrs_count; k++) {
            if (context->naptr_rrs[k].sort_pos == context->position - 1) {
                ast_copy_string(context->dst, context->naptr_rrs[k].result, dstlen);
                ast_copy_string(context->tech, context->naptr_rrs[k].tech, techlen);
                break;
            }
        }
    } else if (!(context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
        context->dst[0] = 0;
    } else if ((context->options & ENUMLOOKUP_OPTIONS_COUNT)) {
        snprintf(context->dst, context->dstlen, "%d", context->naptr_rrs_count + context->count);
    }

    if (chan) {
        ret |= ast_autoservice_stop(chan);
    }

    if (!argcontext) {
        for (k = 0; k < context->naptr_rrs_count; k++) {
            ast_free(context->naptr_rrs[k].result);
            ast_free(context->naptr_rrs[k].tech);
        }
        ast_free(context->naptr_rrs);
        ast_free(context);
    } else {
        *argcontext = context;
    }

    return ret;
}
Example #24
0
static int func_channel_write_real(struct ast_channel *chan, const char *function,
			      char *data, const char *value)
{
	int ret = 0;
	signed char gainset;

	if (!strcasecmp(data, "language"))
		locked_string_field_set(chan, language, value);
	else if (!strcasecmp(data, "parkinglot"))
		locked_string_field_set(chan, parkinglot, value);
	else if (!strcasecmp(data, "musicclass"))
		locked_string_field_set(chan, musicclass, value);
	else if (!strcasecmp(data, "accountcode"))
		locked_string_field_set(chan, accountcode, value);
	else if (!strcasecmp(data, "userfield"))
		locked_string_field_set(chan, userfield, value);
	else if (!strcasecmp(data, "after_bridge_goto")) {
		if (ast_strlen_zero(value)) {
			ast_bridge_discard_after_goto(chan);
		} else {
			ast_bridge_set_after_go_on(chan, ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), value);
		}
	} else if (!strcasecmp(data, "amaflags")) {
		ast_channel_lock(chan);
		if (isdigit(*value)) {
			int amaflags;
			sscanf(value, "%30d", &amaflags);
			ast_channel_amaflags_set(chan, amaflags);
		} else if (!strcasecmp(value,"OMIT")){
			ast_channel_amaflags_set(chan, 1);
		} else if (!strcasecmp(value,"BILLING")){
			ast_channel_amaflags_set(chan, 2);
		} else if (!strcasecmp(value,"DOCUMENTATION")){
			ast_channel_amaflags_set(chan, 3);
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "peeraccount"))
		locked_string_field_set(chan, peeraccount, value);
	else if (!strcasecmp(data, "hangupsource"))
		/* XXX - should we be forcing this here? */
		ast_set_hangupsource(chan, value, 0);
#ifdef CHANNEL_TRACE
	else if (!strcasecmp(data, "trace")) {
		ast_channel_lock(chan);
		if (ast_true(value))
			ret = ast_channel_trace_enable(chan);
		else if (ast_false(value))
			ret = ast_channel_trace_disable(chan);
		else {
			ret = -1;
			ast_log(LOG_WARNING, "Invalid value for CHANNEL(trace).\n");
		}
		ast_channel_unlock(chan);
	}
#endif
	else if (!strcasecmp(data, "tonezone")) {
		struct ast_tone_zone *new_zone;
		if (!(new_zone = ast_get_indication_zone(value))) {
			ast_log(LOG_ERROR, "Unknown country code '%s' for tonezone. Check indications.conf for available country codes.\n", value);
			ret = -1;
		} else {
			ast_channel_lock(chan);
			if (ast_channel_zone(chan)) {
				ast_channel_zone_set(chan, ast_tone_zone_unref(ast_channel_zone(chan)));
			}
			ast_channel_zone_set(chan, ast_tone_zone_ref(new_zone));
			ast_channel_unlock(chan);
			new_zone = ast_tone_zone_unref(new_zone);
		}
	} else if (!strcasecmp(data, "dtmf_features")) {
		ret = ast_bridge_features_ds_set_string(chan, value);
	} else if (!strcasecmp(data, "callgroup")) {
		ast_channel_lock(chan);
		ast_channel_callgroup_set(chan, ast_get_group(value));
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "pickupgroup")) {
		ast_channel_lock(chan);
		ast_channel_pickupgroup_set(chan, ast_get_group(value));
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "namedcallgroup")) {
		struct ast_namedgroups *groups = ast_get_namedgroups(value);

		ast_channel_lock(chan);
		ast_channel_named_callgroups_set(chan, groups);
		ast_channel_unlock(chan);
		ast_unref_namedgroups(groups);
	} else if (!strcasecmp(data, "namedpickupgroup")) {
		struct ast_namedgroups *groups = ast_get_namedgroups(value);

		ast_channel_lock(chan);
		ast_channel_named_pickupgroups_set(chan, groups);
		ast_channel_unlock(chan);
		ast_unref_namedgroups(groups);
	} else if (!strcasecmp(data, "txgain")) {
		sscanf(value, "%4hhd", &gainset);
		ast_channel_setoption(chan, AST_OPTION_TXGAIN, &gainset, sizeof(gainset), 0);
	} else if (!strcasecmp(data, "rxgain")) {
		sscanf(value, "%4hhd", &gainset);
		ast_channel_setoption(chan, AST_OPTION_RXGAIN, &gainset, sizeof(gainset), 0);
	} else if (!strcasecmp(data, "transfercapability")) {
		unsigned short i;

		ast_channel_lock(chan);
		for (i = 0; i < 0x20; i++) {
			if (!strcasecmp(transfercapability_table[i], value) && strcmp(value, "UNK")) {
				ast_channel_transfercapability_set(chan, i);
				break;
			}
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "hangup_handler_pop")) {
		/* Pop one hangup handler before pushing the new handler. */
		ast_pbx_hangup_handler_pop(chan);
		ast_pbx_hangup_handler_push(chan, value);
	} else if (!strcasecmp(data, "hangup_handler_push")) {
		ast_pbx_hangup_handler_push(chan, value);
	} else if (!strcasecmp(data, "hangup_handler_wipe")) {
		/* Pop all hangup handlers before pushing the new handler. */
		while (ast_pbx_hangup_handler_pop(chan)) {
		}
		ast_pbx_hangup_handler_push(chan, value);
	} else if (!strncasecmp(data, "secure_bridge_", 14)) {
		struct ast_datastore *ds;
		struct ast_secure_call_store *store;

		if (!chan || !value) {
			return -1;
		}

		ast_channel_lock(chan);
		if (!(ds = ast_channel_datastore_find(chan, &secure_call_info, NULL))) {
			if (!(ds = ast_datastore_alloc(&secure_call_info, NULL))) {
				ast_channel_unlock(chan);
				return -1;
			}
			if (!(store = ast_calloc(1, sizeof(*store)))) {
				ast_channel_unlock(chan);
				ast_free(ds);
				return -1;
			}
			ds->data = store;
			ast_channel_datastore_add(chan, ds);
		} else {
			store = ds->data;
		}

		if (!strcasecmp(data, "secure_bridge_signaling")) {
			store->signaling = ast_true(value) ? 1 : 0;
		} else if (!strcasecmp(data, "secure_bridge_media")) {
			store->media = ast_true(value) ? 1 : 0;
		}
		ast_channel_unlock(chan);
	} else if (!strcasecmp(data, "max_forwards")) {
		int max_forwards;
		if (sscanf(value, "%d", &max_forwards) != 1) {
			ast_log(LOG_WARNING, "Unable to set max forwards to '%s'\n", value);
			ret = -1;
		} else {
			ast_channel_lock(chan);
			ret = ast_max_forwards_set(chan, max_forwards);
			ast_channel_unlock(chan);
		}
	} else if (!ast_channel_tech(chan)->func_channel_write
		 || ast_channel_tech(chan)->func_channel_write(chan, function, data, value)) {
		ast_log(LOG_WARNING, "Unknown or unavailable item requested: '%s'\n",
				data);
		ret = -1;
	}

	return ret;
}
static int http_callback(struct ast_tcptls_session_instance *ser, const struct ast_http_uri *urih, const char *uri, enum ast_http_method method, struct ast_variable *get_params, struct ast_variable *headers)
{
	char file_name[64] = "/tmp/test-media-cache-XXXXXX";
	struct ast_str *http_header = ast_str_create(128);
	struct ast_str *cache_control = ast_str_create(128);
	int fd = -1;
	int unmodified = 0;
	int send_file = options.send_file && method == AST_HTTP_GET;

	if (!http_header) {
		goto error;
	}

	if (send_file) {
		char buf[1024];

		fd = mkstemp(file_name);
		if (fd == -1) {
			ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno);
			goto error;
		}

		memset(buf, 1, sizeof(buf));
		if (write(fd, buf, sizeof(buf)) != sizeof(buf)) {
			ast_log(LOG_ERROR, "Failed to write expected number of bytes to pipe\n");
			close(fd);
			goto error;
		}
		close(fd);

		fd = open(file_name, 0);
		if (fd == -1) {
			ast_log(LOG_ERROR, "Unable to open temp file for testing: %s (%d)", strerror(errno), errno);
			goto error;
		}
	}

	if (options.cache_control.maxage) {
		SET_OR_APPEND_CACHE_CONTROL(cache_control);
		ast_str_append(&cache_control, 0, "max-age=%d", options.cache_control.maxage);
	}

	if (options.cache_control.s_maxage) {
		SET_OR_APPEND_CACHE_CONTROL(cache_control);
		ast_str_append(&cache_control, 0, "s-maxage=%d", options.cache_control.s_maxage);
	}

	if (options.cache_control.no_cache) {
		SET_OR_APPEND_CACHE_CONTROL(cache_control);
		ast_str_append(&cache_control, 0, "%s", "no-cache");
	}

	if (options.cache_control.must_revalidate) {
		SET_OR_APPEND_CACHE_CONTROL(cache_control);
		ast_str_append(&cache_control, 0, "%s", "must-revalidate");
	}

	if (ast_str_strlen(cache_control)) {
		ast_str_append(&http_header, 0, "%s\r\n", ast_str_buffer(cache_control));
	}

	if (options.expires.tv_sec) {
		struct ast_tm now_time;
		char tmbuf[64];

		ast_localtime(&options.expires, &now_time, NULL);
		ast_strftime(tmbuf, sizeof(tmbuf), "%a, %d %b %Y %T %z", &now_time);
		ast_str_append(&http_header, 0, "Expires: %s\r\n", tmbuf);
	}

	if (!ast_strlen_zero(options.etag)) {
		struct ast_variable *v;

		ast_str_append(&http_header, 0, "ETag: %s\r\n", options.etag);
		for (v = headers; v; v = v->next) {
			if (!strcasecmp(v->name, "If-None-Match") && !strcasecmp(v->value, options.etag)) {
				unmodified = 1;
				break;
			}
		}
	}

	if (!unmodified) {
		ast_http_send(ser, method, options.status_code, options.status_text, http_header, NULL, send_file ? fd : 0, 1);
	} else {
		ast_http_send(ser, method, 304, "Not Modified", http_header, NULL, 0, 1);
	}

	if (send_file) {
		close(fd);
		unlink(file_name);
	}

	ast_free(cache_control);

	return 0;

error:
	ast_free(http_header);
	ast_free(cache_control);
	ast_http_request_close_on_completion(ser);
	ast_http_error(ser, 418, "I'm a Teapot", "Please don't ask me to brew coffee.");

	return 0;
}
/*! \brief Destructor for T.38 state information */
static void t38_state_destroy(void *obj)
{
	ast_free(obj);
}
Example #27
0
void ast_ari_bridges_record(struct ast_variable *headers,
	struct ast_ari_bridges_record_args *args,
	struct ast_ari_response *response)
{
	RAII_VAR(struct ast_bridge *, bridge, find_bridge(response, args->bridge_id), ao2_cleanup);
	RAII_VAR(struct ast_channel *, record_channel, NULL, ast_hangup);
	RAII_VAR(struct stasis_app_control *, control, NULL, ao2_cleanup);
	RAII_VAR(struct stasis_app_recording *, recording, NULL, ao2_cleanup);
	RAII_VAR(char *, recording_url, NULL, ast_free);
	RAII_VAR(struct ast_json *, json, NULL, ast_json_unref);
	RAII_VAR(struct stasis_app_recording_options *, options, NULL, ao2_cleanup);
	RAII_VAR(char *, uri_encoded_name, NULL, ast_free);
	RAII_VAR(struct stasis_forward *, channel_forward, NULL, stasis_forward_cancel);

	struct stasis_topic *channel_topic;
	struct stasis_topic *bridge_topic;
	size_t uri_name_maxlen;
	struct bridge_channel_control_thread_data *thread_data;
	pthread_t threadid;

	ast_assert(response != NULL);

	if (bridge == NULL) {
		return;
	}

	if (!(record_channel = prepare_bridge_media_channel("Recorder"))) {
		ast_ari_response_error(
			response, 500, "Internal Server Error", "Failed to create recording channel");
		return;
	}

	bridge_topic = ast_bridge_topic(bridge);
	channel_topic = ast_channel_topic(record_channel);

	/* Forward messages from the recording channel topic to the bridge topic so that anything listening for
	 * messages on the bridge topic will receive the recording start/stop messages. Other messages that would
	 * go to this channel will be suppressed since the channel is marked as internal.
	 */
	if (!bridge_topic || !channel_topic || !(channel_forward = stasis_forward_all(channel_topic, bridge_topic))) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Could not forward record channel stasis messages to bridge topic");
		return;
	}

	if (ast_unreal_channel_push_to_bridge(record_channel, bridge,
		AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE | AST_BRIDGE_CHANNEL_FLAG_LONELY)) {
		ast_ari_response_error(
			response, 500, "Internal Error", "Failed to put recording channel into the bridge");
		return;
	}

	control = stasis_app_control_create(record_channel);
	if (control == NULL) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	options = stasis_app_recording_options_create(args->name, args->format);
	if (options == NULL) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	ast_string_field_build(options, target, "bridge:%s", args->bridge_id);
	options->max_silence_seconds = args->max_silence_seconds;
	options->max_duration_seconds = args->max_duration_seconds;
	options->terminate_on =
		stasis_app_recording_termination_parse(args->terminate_on);
	options->if_exists =
		stasis_app_recording_if_exists_parse(args->if_exists);
	options->beep = args->beep;

	if (options->terminate_on == STASIS_APP_RECORDING_TERMINATE_INVALID) {
		ast_ari_response_error(
			response, 400, "Bad Request",
			"terminateOn invalid");
		return;
	}

	if (options->if_exists == AST_RECORD_IF_EXISTS_ERROR) {
		ast_ari_response_error(
			response, 400, "Bad Request",
			"ifExists invalid");
		return;
	}

	if (!ast_get_format_for_file_ext(options->format)) {
		ast_ari_response_error(
			response, 422, "Unprocessable Entity",
			"specified format is unknown on this system");
		return;
	}

	recording = stasis_app_control_record(control, options);
	if (recording == NULL) {
		switch(errno) {
		case EINVAL:
			/* While the arguments are invalid, we should have
			 * caught them prior to calling record.
			 */
			ast_ari_response_error(
				response, 500, "Internal Server Error",
				"Error parsing request");
			break;
		case EEXIST:
			ast_ari_response_error(response, 409, "Conflict",
				"Recording '%s' already exists and can not be overwritten",
				args->name);
			break;
		case ENOMEM:
			ast_ari_response_alloc_failed(response);
			break;
		case EPERM:
			ast_ari_response_error(
				response, 400, "Bad Request",
				"Recording name invalid");
			break;
		default:
			ast_log(LOG_WARNING,
				"Unrecognized recording error: %s\n",
				strerror(errno));
			ast_ari_response_error(
				response, 500, "Internal Server Error",
				"Internal Server Error");
			break;
		}
		return;
	}

	uri_name_maxlen = strlen(args->name) * 3;
	uri_encoded_name = ast_malloc(uri_name_maxlen);
	if (!uri_encoded_name) {
		ast_ari_response_alloc_failed(response);
		return;
	}
	ast_uri_encode(args->name, uri_encoded_name, uri_name_maxlen, ast_uri_http);

	if (ast_asprintf(&recording_url, "/recordings/live/%s",
			uri_encoded_name) == -1) {
		recording_url = NULL;
		ast_ari_response_alloc_failed(response);
		return;
	}

	json = stasis_app_recording_to_json(recording);
	if (!json) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	thread_data = ast_calloc(1, sizeof(*thread_data));
	if (!thread_data) {
		ast_ari_response_alloc_failed(response);
		return;
	}

	thread_data->bridge_channel = record_channel;
	thread_data->control = control;
	thread_data->forward = channel_forward;

	if (ast_pthread_create_detached(&threadid, NULL, bridge_channel_control_thread, thread_data)) {
		ast_ari_response_alloc_failed(response);
		ast_free(thread_data);
		return;
	}

	/* These are owned by the other thread now, so we don't want RAII_VAR disposing of them. */
	record_channel = NULL;
	control = NULL;
	channel_forward = NULL;

	ast_ari_response_created(response, recording_url, ast_json_ref(json));
}
/*! \brief Start monitoring a channel
 * \param chan ast_channel struct to record
 * \param format_spec file format to use for recording
 * \param fname_base filename base to record to
 * \param need_lock whether to lock the channel mutex
 * \param stream_action whether to record the input and/or output streams.  X_REC_IN | X_REC_OUT is most often used
 * Creates the file to record, if no format is specified it assumes WAV
 * It also sets channel variable __MONITORED=yes
 * \retval 0 on success
 * \retval -1 on failure
 */
int AST_OPTIONAL_API_NAME(ast_monitor_start)(struct ast_channel *chan, const char *format_spec,
					     const char *fname_base, int need_lock, int stream_action,
					     const char *beep_id)
{
	int res = 0;
	RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);

	LOCK_IF_NEEDED(chan, need_lock);

	if (!(ast_channel_monitor(chan))) {
		struct ast_channel_monitor *monitor;
		char *channel_name, *p;

		/* Create monitoring directory if needed */
		ast_mkdir(ast_config_AST_MONITOR_DIR, 0777);

		if (!(monitor = ast_calloc(1, sizeof(*monitor)))) {
			UNLOCK_IF_NEEDED(chan, need_lock);
			return -1;
		}

		if (!ast_strlen_zero(beep_id)) {
			ast_copy_string(monitor->beep_id, beep_id, sizeof(monitor->beep_id));
		}

		/* Determine file names */
		if (!ast_strlen_zero(fname_base)) {
			int directory = strchr(fname_base, '/') ? 1 : 0;
			const char *absolute = *fname_base == '/' ? "" : ast_config_AST_MONITOR_DIR;
			const char *absolute_suffix = *fname_base == '/' ? "" : "/";

			snprintf(monitor->read_filename, FILENAME_MAX, "%s%s%s-in",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s%s%s-out",
						absolute, absolute_suffix, fname_base);
			snprintf(monitor->filename_base, FILENAME_MAX, "%s%s%s",
					 	absolute, absolute_suffix, fname_base);

			/* try creating the directory just in case it doesn't exist */
			if (directory) {
				char *name = ast_strdupa(monitor->filename_base);
				ast_mkdir(dirname(name), 0777);
			}
		} else {
			ast_mutex_lock(&monitorlock);
			snprintf(monitor->read_filename, FILENAME_MAX, "%s/audio-in-%lu",
						ast_config_AST_MONITOR_DIR, seq);
			snprintf(monitor->write_filename, FILENAME_MAX, "%s/audio-out-%lu",
						ast_config_AST_MONITOR_DIR, seq);
			seq++;
			ast_mutex_unlock(&monitorlock);

			/* Replace all '/' chars from the channel name with '-' chars. */
			channel_name = ast_strdupa(ast_channel_name(chan));
			for (p = channel_name; (p = strchr(p, '/')); ) {
				*p = '-';
			}

			snprintf(monitor->filename_base, FILENAME_MAX, "%s/%d-%s",
					 ast_config_AST_MONITOR_DIR, (int)time(NULL), channel_name);
			monitor->filename_changed = 1;
		}

		monitor->stop = ast_monitor_stop;

		/* Determine file format */
		if (!ast_strlen_zero(format_spec)) {
			monitor->format = ast_strdup(format_spec);
		} else {
			monitor->format = ast_strdup("wav");
		}
		
		/* open files */
		if (stream_action & X_REC_IN) {
			if (ast_fileexists(monitor->read_filename, NULL, NULL) > 0)
				ast_filedelete(monitor->read_filename, NULL);
			if (!(monitor->read_stream = ast_writefile(monitor->read_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->read_filename);
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->read_stream = NULL;

		if (stream_action & X_REC_OUT) {
			if (ast_fileexists(monitor->write_filename, NULL, NULL) > 0) {
				ast_filedelete(monitor->write_filename, NULL);
			}
			if (!(monitor->write_stream = ast_writefile(monitor->write_filename,
							monitor->format, NULL,
							O_CREAT|O_TRUNC|O_WRONLY, 0, AST_FILE_MODE))) {
				ast_log(LOG_WARNING, "Could not create file %s\n",
							monitor->write_filename);
				if (monitor->read_stream) {
					ast_closestream(monitor->read_stream);
				}
				ast_free(monitor);
				UNLOCK_IF_NEEDED(chan, need_lock);
				return -1;
			}
		} else
			monitor->write_stream = NULL;

		ast_channel_insmpl_set(chan, 0);
		ast_channel_outsmpl_set(chan, 0);
		ast_channel_monitor_set(chan, monitor);
		ast_monitor_set_state(chan, AST_MONITOR_RUNNING);
		/* so we know this call has been monitored in case we need to bill for it or something */
		pbx_builtin_setvar_helper(chan, "__MONITORED","true");

		message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
				ast_channel_monitor_start_type(),
				NULL);
		if (message) {
			stasis_publish(ast_channel_topic(chan), message);
		}
	} else {
		ast_debug(1,"Cannot start monitoring %s, already monitored\n", ast_channel_name(chan));
		res = -1;
	}

	UNLOCK_IF_NEEDED(chan, need_lock);

	return res;
}
/*! \brief Destructor for dialog-info+xml information */
static void dialog_info_xml_state_destroy(void *obj)
{
	ast_free(obj);
}
Example #30
0
EXPORT_DEF int at_enque_sms (struct cpvt* cpvt, const char* destination, const char* msg, unsigned validity_minutes, int report_req, void ** id)
{
    ssize_t res;
    char buf[1024] = "AT+CMGS=\"";
    char pdu_buf[2048];
    pvt_t* pvt = cpvt->pvt;

    at_queue_cmd_t at_cmd[] = {
        { CMD_AT_CMGS,    RES_SMS_PROMPT, ATQ_CMD_FLAG_DEFAULT, { ATQ_CMD_TIMEOUT_2S, 0}  , NULL, 0 },
        { CMD_AT_SMSTEXT, RES_OK,         ATQ_CMD_FLAG_DEFAULT, { ATQ_CMD_TIMEOUT_40S, 0} , NULL, 0 }
    };

    if(pvt->use_pdu)
    {
        /* set default validity period */
        if(validity_minutes <= 0)
            validity_minutes = 3 * 24 * 60;
        /*		res = pdu_build(pdu_buf, sizeof(pdu_buf), pvt->sms_scenter, destination, msg, validity_minutes, report_req);
        */
        res = pdu_build(pdu_buf, sizeof(pdu_buf), "", destination, msg, validity_minutes, report_req);
        if(res <= 0)
        {
            if(res == -E2BIG)
            {
                ast_verb (3, "[%s] SMS Message too long, PDU has limit 140 octets\n", PVT_ID(pvt));
                ast_log (LOG_WARNING, "[%s] SMS Message too long, PDU has limit 140 octets\n", PVT_ID(pvt));
            }
            /* TODO: complain on other errors */
            return res;
        }

        if(res > (int)(sizeof(pdu_buf) - 2))
            return -1;

        return at_enque_pdu(cpvt, pdu_buf, NULL, 0, 0, id);
    }
    else
    {
        at_cmd[0].length = 9;

        res = str_recode (RECODE_ENCODE, STR_ENCODING_UCS2_HEX, destination, strlen (destination), buf + at_cmd[0].length, sizeof(buf) - at_cmd[0].length - 3);
        if(res <= 0)
        {
            ast_log (LOG_ERROR, "[%s] Error converting SMS number to UCS-2\n", PVT_ID(pvt));
            return -4;
        }
        at_cmd[0].length += res;
        buf[at_cmd[0].length++] = '"';
        buf[at_cmd[0].length++] = '\r';
        buf[at_cmd[0].length] = '\0';
    }

    at_cmd[0].data = ast_strdup (buf);
    if(!at_cmd[0].data)
        return -ENOMEM;

    res = strlen (msg);

//	if(!pvt->use_pdu)
//	{
    if (pvt->use_ucs2_encoding)
    {
        /* NOTE: bg: i test limit of no response is 133, but for +CMS ERROR: ?  */
        /* message limit in 178 octet of TPDU (w/o SCA) Headers: Type(1)+MR(1)+DA(3..12)+PID(1)+DCS(1)+VP(0,1,7)+UDL(1) = 8..24 (usually 14)  */
        if(res > 70)
        {
            ast_log (LOG_ERROR, "[%s] SMS message too long, 70 symbols max\n", PVT_ID(pvt));
            return -4;
        }

        res = str_recode (RECODE_ENCODE, STR_ENCODING_UCS2_HEX, msg, res, pdu_buf, sizeof(pdu_buf) - 2);
        if (res < 0)
        {
            ast_free (at_cmd[0].data);
            ast_log (LOG_ERROR, "[%s] Error converting SMS to UCS-2: '%s'\n", PVT_ID(pvt), msg);
            return -4;
        }
        pdu_buf[res++] = 0x1a;
        pdu_buf[res] = 0;
        at_cmd[1].length = res;
    }
    else
    {
        if(res > 140)
        {
            ast_log (LOG_ERROR, "[%s] SMS message too long, 140 symbols max\n", PVT_ID(pvt));
            return -4;
        }

        at_cmd[1].length = snprintf (pdu_buf, sizeof(pdu_buf), "%.160s\x1a", msg);
    }
//	}

    at_cmd[1].data = ast_strdup(pdu_buf);
    if(!at_cmd[1].data)
    {
        ast_free(at_cmd[0].data);
        return -ENOMEM;
    }

    return at_queue_insert_task(cpvt, at_cmd, ITEMS_OF(at_cmd), 0, (struct at_queue_task **)id);
}