/**
 * Start execution of mixer record component
 */
static iks *start_mixer_record_component(struct rayo_actor *client, struct rayo_actor *mixer, iks *iq, void *data)
{
	struct rayo_component *component = NULL;
	iks *record = iks_find(iq, "record");

	component = record_component_create(mixer, iks_find_attrib(iq, "from"), record);
	if (!component) {
		return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
	}

	/* mixer doesn't allow "send" */
	if (!strcmp("send", iks_find_attrib_soft(record, "direction"))) {
		RAYO_UNLOCK(component);
		RAYO_DESTROY(component);
		return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
	}

	if (start_mixer_record(component)) {
		rayo_component_send_start(component, iq);
	} else {
		RAYO_UNLOCK(component);
		RAYO_DESTROY(component);
		return iks_new_error(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR);
	}

	return NULL;
}
/**
 * Create new output component
 */
static struct rayo_component *create_output_component(struct rayo_actor *actor, const char *type, iks *output, const char *client_jid)
{
	switch_memory_pool_t *pool;
	struct output_component *output_component = NULL;

	switch_core_new_memory_pool(&pool);
	output_component = switch_core_alloc(pool, sizeof(*output_component));
	output_component = OUTPUT_COMPONENT(rayo_component_init((struct rayo_component *)output_component, pool, type, "output", NULL, actor, client_jid));
	if (output_component) {
		output_component->document = iks_copy(output);
		output_component->start_offset_ms = iks_find_int_attrib(output, "start-offset");
		output_component->repeat_interval_ms = iks_find_int_attrib(output, "repeat-interval");
		output_component->repeat_times = iks_find_int_attrib(output, "repeat-times");
		output_component->max_time_ms = iks_find_int_attrib(output, "max-time");
		output_component->start_paused = iks_find_bool_attrib(output, "start-paused");
		output_component->renderer = switch_core_strdup(RAYO_POOL(output_component), iks_find_attrib_soft(output, "renderer"));
		/* get custom headers */
		{
			switch_stream_handle_t headers = { 0 };
			iks *header = NULL;
			int first = 1;
			SWITCH_STANDARD_STREAM(headers);
			for (header = iks_find(output, "header"); header; header = iks_next_tag(header)) {
				if (!strcmp("header", iks_name(header))) {
					const char *name = iks_find_attrib_soft(header, "name");
					const char *value = iks_find_attrib_soft(header, "value");
					if (!zstr(name) && !zstr(value)) {
						headers.write_function(&headers, "%s%s=%s", first ? "{" : ",", name, value);
						first = 0;
					}
				}
			}
			if (headers.data) {
				headers.write_function(&headers, "}");
				output_component->headers = switch_core_strdup(RAYO_POOL(output_component), (char *)headers.data);
				free(headers.data);
			}
		}
	} else {
		switch_core_destroy_memory_pool(&pool);
	}

	return RAYO_COMPONENT(output_component);
}
/**
 * Forward result
 */
static iks *prompt_component_handle_result(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
	iks *iq = msg->payload;

	/* forward all results, except for internal ones... */
	if (strncmp("mod_rayo-prompt", iks_find_attrib_soft(iq, "id"), 15)) {
		iks_insert_attrib(iq, "from", RAYO_JID(prompt));
		iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid);
		RAYO_SEND_REPLY_DUP(prompt, RAYO_COMPONENT(prompt)->client_jid, iq);
	}
	return NULL;
}
Example #4
0
/**
 * Forward result
 */
static iks *prompt_component_handle_result(struct rayo_actor *prompt, struct rayo_message *msg, void *data)
{
	iks *iq = msg->payload;

	/* forward all results, except for internal ones... */
	const char *id = iks_find_attrib_soft(iq, "id");
	if (strncmp("mod_rayo-prompt", id, 15)) {
		iks_insert_attrib(iq, "from", RAYO_JID(prompt));
		iks_insert_attrib(iq, "to", RAYO_COMPONENT(prompt)->client_jid);
		RAYO_SEND_REPLY_DUP(prompt, RAYO_COMPONENT(prompt)->client_jid, iq);
	} else if (!strcmp(PROMPT_COMPONENT(prompt)->start_timers_request_id, id)) {
		rayo_component_send_input_timers_started_event(RAYO_COMPONENT(prompt));
	}

	return NULL;
}
/**
 * Create a record component
 */
static struct rayo_component *record_component_create(struct rayo_actor *actor, const char *client_jid, iks *record)
{
	switch_memory_pool_t *pool;
	struct record_component *record_component = NULL;
	char *local_file_path;
	char *fs_file_path;
	switch_bool_t start_paused;

	/* validate record attributes */
	if (!VALIDATE_RAYO_RECORD(record)) {
		return NULL;
	}

	start_paused = iks_find_bool_attrib(record, "start-paused");

	/* create record filename from session UUID and ref */
	/* for example: prefix/1234-1234-1234-1234-30.wav */
	local_file_path = switch_mprintf("%s%s-%i.%s",
		globals.record_file_prefix,
		actor->id, rayo_actor_seq_next(actor), iks_find_attrib(record, "format"));

	fs_file_path = switch_mprintf("{pause=%s}fileman://%s",
		start_paused ? "true" : "false",
		local_file_path);

	switch_core_new_memory_pool(&pool);
	record_component = switch_core_alloc(pool, sizeof(*record_component));
	rayo_component_init(RAYO_COMPONENT(record_component), pool, "record", fs_file_path, actor, client_jid);
	record_component->max_duration = iks_find_int_attrib(record, "max-duration");
	record_component->initial_timeout = iks_find_int_attrib(record, "initial-timeout");
	record_component->final_timeout = iks_find_int_attrib(record, "final-timeout");
	record_component->direction = switch_core_strdup(RAYO_POOL(record_component), iks_find_attrib_soft(record, "direction"));
	record_component->mix = iks_find_bool_attrib(record, "mix");
	record_component->start_beep = iks_find_bool_attrib(record, "start-beep");
	record_component->stop_beep = iks_find_bool_attrib(record, "stop-beep");
	record_component->start_time = start_paused ? 0 : switch_micro_time_now();
	record_component->local_file_path = switch_core_strdup(RAYO_POOL(record_component), local_file_path);

	switch_safe_free(local_file_path);
	switch_safe_free(fs_file_path);

	return RAYO_COMPONENT(record_component);
}
Example #6
0
/**
 * Start CPA
 */
iks *rayo_cpa_component_start(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
{
    iks *iq = msg->payload;
    switch_core_session_t *session = (switch_core_session_t *)session_data;
    iks *input = iks_find(iq, "input");
    switch_memory_pool_t *pool = NULL;
    struct cpa_component *component = NULL;
    int have_grammar = 0;
    iks *grammar = NULL;

    /* create CPA component */
    switch_core_new_memory_pool(&pool);
    component = switch_core_alloc(pool, sizeof(*component));
    component = CPA_COMPONENT(rayo_component_init((struct rayo_component *)component, pool, RAT_CALL_COMPONENT, "cpa", NULL, call, iks_find_attrib(iq, "from")));
    if (!component) {
        switch_core_destroy_memory_pool(&pool);
        return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "Failed to create CPA entity");
    }

    switch_core_hash_init(&component->signals);

    /* start CPA detectors */
    for (grammar = iks_find(input, "grammar"); grammar; grammar = iks_next_tag(grammar)) {
        if (!strcmp("grammar", iks_name(grammar))) {
            const char *error_str = "";
            const char *url = iks_find_attrib_soft(grammar, "url");
            char *url_dup;
            char *url_params;

            if (zstr(url)) {
                stop_cpa_detectors(component);
                RAYO_UNLOCK(component);
                RAYO_DESTROY(component);
                return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Missing grammar URL");
            }
            have_grammar = 1;

            url_dup = strdup(url);
            if ((url_params = strchr(url_dup, '?'))) {
                *url_params = '\0';
                url_params++;
            }

            if (switch_core_hash_find(component->signals, url)) {
                free(url_dup);
                stop_cpa_detectors(component);
                RAYO_UNLOCK(component);
                RAYO_DESTROY(component);
                return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "Duplicate URL");
            }

            /* start detector */
            /* TODO return better reasons... */
            if (rayo_cpa_detector_start(switch_core_session_get_uuid(session), url_dup, &error_str)) {
                struct cpa_signal *cpa_signal = switch_core_alloc(pool, sizeof(*cpa_signal));
                cpa_signal->terminate = !zstr(url_params) && strstr(url_params, "terminate=true");
                cpa_signal->name = switch_core_strdup(pool, url_dup);
                switch_core_hash_insert(component->signals, cpa_signal->name, cpa_signal);
                subscribe(switch_core_session_get_uuid(session), cpa_signal->name, RAYO_JID(component));
            } else {
                free(url_dup);
                stop_cpa_detectors(component);
                RAYO_UNLOCK(component);
                RAYO_DESTROY(component);
                return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, error_str);
            }

            free(url_dup);
        }
    }

    if (!have_grammar) {
        stop_cpa_detectors(component);
        RAYO_UNLOCK(component);
        RAYO_DESTROY(component);
        return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "No grammar defined");
    }

    /* acknowledge command */
    rayo_component_send_start(RAYO_COMPONENT(component), iq);

    /* TODO hangup race condition */
    subscribe(switch_core_session_get_uuid(session), "hangup", RAYO_JID(component));

    /* ready to forward detector events */
    component->ready = 1;

    return NULL;
}
/**
 * Start execution of call sendfax component
 * @param call the call to send fax to
 * @param msg the original request
 * @param session_data the call's session
 */
static iks *start_sendfax_component(struct rayo_actor *call, struct rayo_message *msg, void *session_data)
{
	iks *iq = msg->payload;
	switch_core_session_t *session = (switch_core_session_t *)session_data;
	struct fax_component *sendfax_component = NULL;
	iks *sendfax = iks_find(iq, "sendfax");
	iks *response = NULL;
	switch_event_t *execute_event = NULL;
	switch_channel_t *channel = switch_core_session_get_channel(session);
	switch_memory_pool_t *pool;
	iks *document;
	const char *fax_document;
	const char *fax_header;
	const char *fax_identity;
	const char *pages;

	/* validate attributes */
	if (!VALIDATE_RAYO_SENDFAX(sendfax)) {
		return iks_new_error(iq, STANZA_ERROR_BAD_REQUEST);
	}

	/* fax is only allowed if the call is not currently joined */
	if (rayo_call_is_joined(RAYO_CALL(call))) {
		return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "can't send fax on a joined call");
	}

	if (rayo_call_is_faxing(RAYO_CALL(call))) {
		return iks_new_error_detailed(iq, STANZA_ERROR_UNEXPECTED_REQUEST, "fax already in progress");
	}

	/* get fax document */
	document = iks_find(sendfax, "document");
	if (!document) {
		return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document");
	}
	fax_document = iks_find_attrib_soft(document, "url");
	if (zstr(fax_document)) {
		return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "missing document url");
	}

	/* is valid URL type? */
	if (!strncasecmp(fax_document, "http://", 7) || !strncasecmp(fax_document, "https://", 8)) {
		switch_stream_handle_t stream = { 0 };
		SWITCH_STANDARD_STREAM(stream);
		/* need to fetch document from server... */
		switch_api_execute("http_get", fax_document, session, &stream);
		if (!zstr(stream.data) && !strncmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) {
			fax_document = switch_core_session_strdup(session, stream.data);
		} else {
			switch_safe_free(stream.data);
			return iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to fetch document");
		}
		switch_safe_free(stream.data);
	} else if (!strncasecmp(fax_document, "file://", 7)) {
		fax_document = fax_document + 7;
		if (zstr(fax_document)) {
			return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid file:// url");
		}
	} else if (strncasecmp(fax_document, SWITCH_PATH_SEPARATOR, strlen(SWITCH_PATH_SEPARATOR))) {
		return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "unsupported url type");
	}

	/* does document exist? */
	if (switch_file_exists(fax_document, pool) != SWITCH_STATUS_SUCCESS) {
		return iks_new_error_detailed_printf(iq, STANZA_ERROR_BAD_REQUEST, "file not found: %s", fax_document);
	}

	/* get fax identity and header */
	fax_identity = iks_find_attrib_soft(document, "identity");
	if (!zstr(fax_identity)) {
		switch_channel_set_variable(channel, "fax_ident", fax_identity);
	} else {
		switch_channel_set_variable(channel, "fax_ident", NULL);
	}
	fax_header = iks_find_attrib_soft(document, "header");
	if (!zstr(fax_header)) {
		switch_channel_set_variable(channel, "fax_header", fax_header);
	} else {
		switch_channel_set_variable(channel, "fax_header", NULL);
	}

	/* get pages to send */
	pages = iks_find_attrib_soft(document, "pages");
	if (!zstr(pages)) {
		if (switch_regex_match(pages, "[1-9][0-9]*(-[1-9][0-9]*)?") == SWITCH_STATUS_FALSE) {
			return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value");
		} else {
			int start = 0;
			int end = 0;
			char *pages_dup = switch_core_session_strdup(session, pages);
			char *sep = strchr(pages_dup, '-');
			if (sep) {
				*sep = '\0';
				sep++;
				end = atoi(sep);
			}
			start = atoi(pages_dup);
			if (end && end < start) {
				return iks_new_error_detailed(iq, STANZA_ERROR_BAD_REQUEST, "invalid pages value");
			}
			switch_channel_set_variable(channel, "fax_start_page", pages_dup);
			switch_channel_set_variable(channel, "fax_end_page", sep);
		}
	} else {
		switch_channel_set_variable(channel, "fax_start_page", NULL);
		switch_channel_set_variable(channel, "fax_end_page", NULL);
	}

	/* create sendfax component */
	switch_core_new_memory_pool(&pool);
	sendfax_component = switch_core_alloc(pool, sizeof(*sendfax_component));
	rayo_component_init((struct rayo_component *)sendfax_component, pool, RAT_CALL_COMPONENT, "sendfax", NULL, call, iks_find_attrib(iq, "from"));

	/* add channel variable so that fax component can be located from fax events */
	switch_channel_set_variable(channel, "rayo_fax_jid", RAYO_JID(sendfax_component));

	/* clear fax result variables */
	switch_channel_set_variable(channel, "fax_success", NULL);
	switch_channel_set_variable(channel, "fax_result_code", NULL);
	switch_channel_set_variable(channel, "fax_result_text", NULL);
	switch_channel_set_variable(channel, "fax_document_transferred_pages", NULL);
	switch_channel_set_variable(channel, "fax_document_total_pages", NULL);
	switch_channel_set_variable(channel, "fax_image_resolution", NULL);
	switch_channel_set_variable(channel, "fax_image_size", NULL);
	switch_channel_set_variable(channel, "fax_bad_rows", NULL);
	switch_channel_set_variable(channel, "fax_transfer_rate", NULL);
	switch_channel_set_variable(channel, "fax_ecm_used", NULL);
	switch_channel_set_variable(channel, "fax_local_station_id", NULL);
	switch_channel_set_variable(channel, "fax_remote_station_id", NULL);

	/* clear fax interrupt variable */
	switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);

	rayo_call_set_faxing(RAYO_CALL(call), 1);

	/* execute txfax APP */
	if (switch_event_create(&execute_event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) {
		switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "call-command", "execute");
		switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-name", "txfax");
		switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "execute-app-arg", fax_document);
		if (!switch_channel_test_flag(channel, CF_PROXY_MODE)) {
			switch_channel_set_flag(channel, CF_BLOCK_BROADCAST_UNTIL_MEDIA);
		}

		if (switch_core_session_queue_private_event(session, &execute_event, SWITCH_FALSE) != SWITCH_STATUS_SUCCESS) {
			response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to txfax (queue event failed)");
			if (execute_event) {
				switch_event_destroy(&execute_event);
			}
			rayo_call_set_faxing(RAYO_CALL(call), 0);
			RAYO_UNLOCK(sendfax_component);
		} else {
			/* component starting... */
			rayo_component_send_start(RAYO_COMPONENT(sendfax_component), iq);
		}
	} else {
		response = iks_new_error_detailed(iq, STANZA_ERROR_INTERNAL_SERVER_ERROR, "failed to create txfax event");
		rayo_call_set_faxing(RAYO_CALL(call), 0);
		RAYO_UNLOCK(sendfax_component);
	}

	return response;
}