SWITCH_DECLARE(const char *) API::executeString(const char *cmd)
{
	char *arg;
	switch_stream_handle_t stream = { 0 };
	char *mycmd = NULL;

	this_check("");

	mycmd = strdup(cmd);

	switch_assert(mycmd);

	if ((arg = strchr(mycmd, ' '))) {
		*arg++ = '\0';
	}

	switch_safe_free(last_data);
	
	SWITCH_STANDARD_STREAM(stream);
	switch_api_execute(mycmd, arg, NULL, &stream);
	last_data = (char *) stream.data;
	switch_safe_free(mycmd);
	return last_data;
}
switch_status_t utils_stop_sofia_profile(char *profile_name)
{
    char arg[128];
    switch_stream_handle_t mystream = { 0 };

    if (!zstr(profile_name)) {
        switch_snprintf(arg, sizeof(arg),"profile %s stop",profile_name);
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"sofia %s\n", arg);
        SWITCH_STANDARD_STREAM(mystream);

        if (switch_api_execute("sofia", arg, NULL, &mystream) != SWITCH_STATUS_SUCCESS) {
            switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"cannot stop profile %s\n", profile_name);
            return SWITCH_STATUS_FALSE;
        }

        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,"profile %s stopped\n", profile_name);
        switch_safe_free(mystream.data);
        return SWITCH_STATUS_SUCCESS;
    } else {
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Invalid profile name\n");
        return SWITCH_STATUS_FALSE;
    }
    return SWITCH_STATUS_FALSE;
}
static switch_xml_t xml_url_fetch(const char *section, const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params,
								  void *user_data)
{
	switch_xml_t xml = NULL;
	char *data = NULL;
	xml_binding_t *binding = (xml_binding_t *) user_data;
	char hostname[256] = "";
	char basic_data[512];
	unsigned char buf[16336] = "";
	ssize_t len = -1, bytes = 0;
	scgi_handle_t handle = { 0 };
	switch_stream_handle_t stream = { 0 };
	char *txt = NULL;

	strncpy(hostname, switch_core_get_switchname(), sizeof(hostname));

	if (!binding) {
		return NULL;
	}

	switch_snprintf(basic_data, sizeof(basic_data), "hostname=%s&section=%s&tag_name=%s&key_name=%s&key_value=%s",
					hostname, section, switch_str_nil(tag_name), switch_str_nil(key_name), switch_str_nil(key_value));

	data = switch_event_build_param_string(params, basic_data, binding->vars_map);
	switch_assert(data);

	scgi_add_param(&handle, "REQUEST_METHOD", "POST");
	scgi_add_param(&handle, "SERVER_PROTOCOL", "HTTP/1.0");
	scgi_add_param(&handle, "REQUEST_URI", binding->uri);
	scgi_add_body(&handle, data);

	if (scgi_connect(&handle, binding->host, binding->port, binding->timeout * 1000) == SCGI_SUCCESS) {
		scgi_send_request(&handle);

		SWITCH_STANDARD_STREAM(stream);
		txt = (char *) stream.data;

		while((len = scgi_recv(&handle, buf, sizeof(buf))) > 0) {
			char *expanded = switch_event_expand_headers(params, (char *)buf);
			
			bytes += len;

			if (bytes > XML_SCGI_MAX_BYTES) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Data too big!\n");
				len = -1;
				break;
			}

			stream.write_function(&stream, "%s", expanded);
			txt = (char *) stream.data;

			if (expanded != (char *)buf) {
				free(expanded);
			}
			
			memset(buf, 0, sizeof(buf));
		}

		scgi_disconnect(&handle);

		if (len < 0 && (!txt || !strlen(txt))) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DEBUG:\nURL: %s Connection Read Failed: [%s]\n", binding->url, handle.err);
			goto end;
		}

	} else {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DEBUG:\nURL: %s Connection Failed: [%s]\n", binding->url, handle.err);
		goto end;
	}

	

	if (GLOBAL_DEBUG) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DEBUG:\nURL: %s\nPOST_DATA:\n%s\n\nRESPONSE:\n-----\n%s\n-----\n", 
						  binding->url, data, switch_str_nil(txt));
	}

	

	if (bytes && txt) {
		if (!(xml = switch_xml_parse_str_dynamic(txt, FALSE))) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Parsing Result! [%s]\ndata: [%s] RESPONSE[%s]\n", 
							  binding->url, data, switch_str_nil(txt));
		}
		txt = NULL;
	} else {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received error trying to fetch %s\ndata: [%s] RESPONSE [%s]\n", 
						  binding->url, data, switch_str_nil(txt));
	}


 end:
	
	switch_safe_free(data);
	switch_safe_free(txt);
	
	return xml;
}
static long do_lookup_url(switch_memory_pool_t *pool, switch_event_t *event, char **response, const char *query, struct curl_httppost *post,
						  switch_curl_slist_t *headers, int timeout)
{
	switch_time_t start_time = switch_micro_time_now();
	switch_time_t time_diff = 0;
	CURL *curl_handle = NULL;
	long httpRes = 0;

	struct http_data http_data;

	memset(&http_data, 0, sizeof(http_data));

	http_data.max_bytes = 10240;
	SWITCH_STANDARD_STREAM(http_data.stream);

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG10, "url: %s\n", query);
	curl_handle = switch_curl_easy_init();

	switch_curl_easy_setopt(curl_handle, CURLOPT_VERBOSE, 0);
	switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);

	if (!strncasecmp(query, "https", 5)) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
		switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
	}
	if (post) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPPOST, post);
	} else {
		switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1);
	}
	if (headers) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
	}
	switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
	switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10);
	/*
	   TIMEOUT_MS is introduced in 7.16.2, we have 7.16.0 in tree 
	 */
#ifdef CURLOPT_TIMEOUT_MS
	if (timeout > 0) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, timeout);
	} else {
		switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT_MS, globals.curl_timeout);
	}
#else
	if (timeout > 0) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, timeout);
	} else {
		switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, globals.curl_timeout / 1000);
	}
#endif
	switch_curl_easy_setopt(curl_handle, CURLOPT_URL, query);
	switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, file_callback);
	switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) &http_data);
	switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-cidlookup/1.0");

	switch_curl_easy_perform(curl_handle);
	switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes);
	switch_curl_easy_cleanup(curl_handle);

	if (http_data.stream.data && !zstr((char *) http_data.stream.data) && strcmp(" ", http_data.stream.data)) {

		/* don't return UNKNOWN */
		if (strcmp("UNKNOWN", http_data.stream.data) || strcmp("UNAVAILABLE", http_data.stream.data)) {
			*response = switch_core_strdup(pool, http_data.stream.data);
		}
	}

	time_diff = (switch_micro_time_now() - start_time);	/* convert to milli from micro */

	if ((time_diff / 1000) >= globals.curl_warnduration) {
		switch_core_time_duration_t duration;
		switch_core_measure_time(time_diff, &duration);
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "SLOW LOOKUP ("
						  "%um, " "%us, " "%ums" "): url: %s\n", duration.min, duration.sec, duration.ms, query);
	}

	switch_safe_free(http_data.stream.data);
	return httpRes;
}
/**
 * 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;
}
/**
 * Handle fax completion event from FreeSWITCH core
 * @param event received from FreeSWITCH core.  It will be destroyed by the core after this function returns.
 */
static void on_execute_complete_event(switch_event_t *event)
{
	const char *application = switch_event_get_header(event, "Application");
	
	if (!zstr(application) && (!strcmp(application, "rxfax") || !strcmp(application, "txfax"))) {
		int is_rxfax = !strcmp(application, "rxfax");
		const char *uuid = switch_event_get_header(event, "Unique-ID");
		const char *fax_jid = switch_event_get_header(event, "variable_rayo_fax_jid");
		struct rayo_actor *component;
		if (!zstr(fax_jid) && (component = RAYO_LOCATE(fax_jid))) {
			iks *result;
			iks *complete;
			iks *fax;
			int have_fax_document = 1;
			switch_core_session_t *session;
			switch_log_printf(SWITCH_CHANNEL_UUID_LOG(uuid), SWITCH_LOG_DEBUG, "Got result for %s\n", fax_jid);

			/* clean up channel */
			session = switch_core_session_locate(uuid);
			if (session) {
				switch_channel_set_variable(switch_core_session_get_channel(session), "rayo_read_frame_interrupt", NULL);
				switch_core_session_rwunlock(session);
			}

			/* RX only: transfer HTTP document and delete local copy */
			if (is_rxfax && RECEIVEFAX_COMPONENT(component)->http_put_after_receive && switch_file_exists(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component)) == SWITCH_STATUS_SUCCESS) {
				switch_stream_handle_t stream = { 0 };
				SWITCH_STANDARD_STREAM(stream);
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename);
				switch_api_execute("http_put", RECEIVEFAX_COMPONENT(component)->filename, NULL, &stream);
				/* check if successful */
				if (!zstr(stream.data) && strncmp(stream.data, "+OK", 3)) {
					/* PUT failed */
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s PUT fax to %s failed: %s\n", RAYO_JID(component), RECEIVEFAX_COMPONENT(component)->filename, (char *)stream.data);
					have_fax_document = 0;
				}
				switch_safe_free(stream.data)
				switch_file_remove(RECEIVEFAX_COMPONENT(component)->local_filename, RAYO_POOL(component));
			}

			/* successful fax? */
			if (have_fax_document && switch_true(switch_event_get_header(event, "variable_fax_success"))) {
				result = rayo_component_create_complete_event(RAYO_COMPONENT(component), FAX_FINISH);
			} else if (have_fax_document && FAX_COMPONENT(component)->stop)  {
				result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_STOP);
			} else {
				result = rayo_component_create_complete_event(RAYO_COMPONENT(component), COMPONENT_COMPLETE_ERROR);
			}
			complete = iks_find(result, "complete");

			/* RX only: add fax document information */
			if (is_rxfax && have_fax_document) {
				const char *pages = switch_event_get_header(event, "variable_fax_document_transferred_pages");
				if (!zstr(pages) && switch_is_number(pages) && atoi(pages) > 0) {
					const char *resolution = switch_event_get_header(event, "variable_fax_file_image_resolution");
					const char *size = switch_event_get_header(event, "variable_fax_image_size");

					fax = iks_insert(complete, "fax");
					iks_insert_attrib(fax, "xmlns", RAYO_FAX_COMPLETE_NS);

					if (RECEIVEFAX_COMPONENT(component)->http_put_after_receive) {
						iks_insert_attrib(fax, "url", RECEIVEFAX_COMPONENT(component)->filename);
					} else {
						/* convert absolute path to file:// URI */
						iks_insert_attrib_printf(fax, "url", "file://%s", RECEIVEFAX_COMPONENT(component)->filename);
					}

					if (!zstr(resolution)) {
						iks_insert_attrib(fax, "resolution", resolution);
					}
					if (!zstr(size)) {
						iks_insert_attrib(fax, "size", size);
					}
					iks_insert_attrib(fax, "pages", pages);
				}
			}

			/* add metadata from event */
			insert_fax_metadata(event, "fax_success", complete);
			insert_fax_metadata(event, "fax_result_code", complete);
			insert_fax_metadata(event, "fax_result_text", complete);
			insert_fax_metadata(event, "fax_document_transferred_pages", complete);
			insert_fax_metadata(event, "fax_document_total_pages", complete);
			insert_fax_metadata(event, "fax_image_resolution", complete);
			insert_fax_metadata(event, "fax_image_size", complete);
			insert_fax_metadata(event, "fax_bad_rows", complete);
			insert_fax_metadata(event, "fax_transfer_rate", complete);
			insert_fax_metadata(event, "fax_ecm_used", complete);
			insert_fax_metadata(event, "fax_local_station_id", complete);
			insert_fax_metadata(event, "fax_remote_station_id", complete);

			/* flag faxing as done */
			rayo_call_set_faxing(RAYO_CALL(RAYO_COMPONENT(component)->parent), 0);

			rayo_component_send_complete_event(RAYO_COMPONENT(component), result);

			RAYO_UNLOCK(component);
		}
	}
}
Exemple #7
0
SWITCH_DECLARE_CONSTRUCTOR Stream::Stream()
{
	SWITCH_STANDARD_STREAM(mystream);
	stream_p = &mystream;
	mine = 1;
}
Exemple #8
0
static http_data_t *do_lookup_url(switch_memory_pool_t *pool, const char *url, const char *method, const char *data, const char *content_type, curl_options_t *options)
{
	switch_CURL *curl_handle = NULL;
	long httpRes = 0;
	http_data_t *http_data = NULL;
	switch_curl_slist_t *headers = NULL;

	http_data = switch_core_alloc(pool, sizeof(http_data_t));
	memset(http_data, 0, sizeof(http_data_t));
	http_data->pool = pool;

	http_data->max_bytes = 64000;
	SWITCH_STANDARD_STREAM(http_data->stream);

	if (!method) {
		method = "get";
	}

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "method: %s, url: %s, content-type: %s\n", method, url, content_type);
	curl_handle = switch_curl_easy_init();

	if (options) {
		if (options->connect_timeout) {
			switch_curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, options->connect_timeout);
		}

		if (options->timeout) {
			switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, options->timeout);
		}
	}

	if (!strncasecmp(url, "https", 5)) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
		switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
	}
	if (!strcasecmp(method, "head")) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_NOBODY, 1);
	} else if (!strcasecmp(method, "post")) {
		switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, strlen(data));
		switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, (void *) data);
		if (content_type) {
			char *ct = switch_mprintf("Content-Type: %s", content_type);
			headers = switch_curl_slist_append(headers, ct);
			switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers);
			switch_safe_free(ct);
		}
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Post data: %s\n", data);
	} else {
		switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPGET, 1);
	}
	switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1);
	switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 15);
	switch_curl_easy_setopt(curl_handle, CURLOPT_URL, url);
	switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1);
	switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, file_callback);
	switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *) http_data);
	switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback);
	switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *) http_data);
	switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-curl/1.0");

	switch_curl_easy_perform(curl_handle);
	switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes);
	switch_curl_easy_cleanup(curl_handle);
	switch_curl_slist_free_all(headers);

	if (http_data->stream.data && !zstr((char *) http_data->stream.data) && strcmp(" ", http_data->stream.data)) {

		http_data->http_response = switch_core_strdup(pool, http_data->stream.data);
	}

	http_data->http_response_code = httpRes;

	switch_safe_free(http_data->stream.data);
	return http_data;
}
Exemple #9
0
static int oreka_send_sip_message(oreka_session_t *oreka, oreka_recording_status_t status, oreka_stream_type_t type)
{
	switch_stream_handle_t sip_header = { 0 };
	switch_stream_handle_t sdp = { 0 };
	switch_stream_handle_t udp_packet = { 0 };
	switch_caller_profile_t *caller_profile = NULL;
	switch_channel_t *channel = NULL;
	switch_event_t *extra_headers = NULL;
	switch_event_header_t *ei = NULL;
	switch_core_session_t *session = oreka->session;
	const char *method = status == FS_OREKA_START ? "INVITE" : "BYE";
	const char *session_uuid = switch_core_session_get_uuid(oreka->session);
	const char *caller_id_number = NULL;
	const char *caller_id_name = NULL;
	const char *callee_id_number = NULL;
	const char *callee_id_name = NULL;
	int rc = 0;

	channel = switch_core_session_get_channel(session);

	SWITCH_STANDARD_STREAM(sip_header);
	SWITCH_STANDARD_STREAM(sdp);
	SWITCH_STANDARD_STREAM(udp_packet);

	extra_headers = get_extra_headers(oreka, status);

	caller_profile = switch_channel_get_caller_profile(channel);

	/* Get caller meta data */
	caller_id_number = switch_caller_get_field_by_name(caller_profile, "caller_id_number");
	
	caller_id_name = switch_caller_get_field_by_name(caller_profile, "caller_id_name");
	if (zstr(caller_id_name)) {
		caller_id_name = caller_id_number;
	}

	callee_id_number = switch_caller_get_field_by_name(caller_profile, "callee_id_number");
	if (zstr(callee_id_number)) {
		callee_id_number = switch_caller_get_field_by_name(caller_profile, "destination_number");
	}

	callee_id_name = switch_caller_get_field_by_name(caller_profile, "callee_id_name");
	if (zstr(callee_id_name)) {
		callee_id_name = callee_id_number;
	}

	/* Setup the RTP */
	if (status == FS_OREKA_START) {
		if (oreka_setup_rtp(oreka, type)) {
			rc = -1;
			goto done;
		}
	}

	if (status == FS_OREKA_STOP) {
		oreka_tear_down_rtp(oreka, type);
	}

	/* Fill in the SDP first if this is the beginning */
	if (status == FS_OREKA_START) {
		sdp.write_function(&sdp, "v=0\r\n");
		sdp.write_function(&sdp, "o=freeswitch %s 1 IN IP4 %s\r\n", session_uuid, globals.local_ipv4_str);
		sdp.write_function(&sdp, "c=IN IP4 %s\r\n", globals.sip_server_ipv4_str);
		sdp.write_function(&sdp, "s=Phone Recording (%s)\r\n", type == FS_OREKA_READ ? "RX" : "TX");
		sdp.write_function(&sdp, "i=FreeSWITCH Oreka Recorder (pid=%d)\r\n", globals.our_pid);
		sdp.write_function(&sdp, "m=audio %d RTP/AVP 0\r\n", type == FS_OREKA_READ ? oreka->read_rtp_port : oreka->write_rtp_port);
		sdp.write_function(&sdp, "a=rtpmap:0 PCMU/%d\r\n", type == FS_OREKA_READ 
				? oreka->read_impl.samples_per_second : oreka->write_impl.samples_per_second);
	}

	/* Request line */
	sip_header.write_function(&sip_header, "%s sip:%s@%s:5060 SIP/2.0\r\n", method, callee_id_name, globals.local_ipv4_str);

	/* Via */
	sip_header.write_function(&sip_header, "Via: SIP/2.0/UDP %s:5061;branch=z9hG4bK-%s\r\n", globals.local_ipv4_str, session_uuid);

	/* From */
	sip_header.write_function(&sip_header, "From: <sip:%s@%s:5061;tag=1>\r\n", caller_id_number, globals.local_ipv4_str);

	/* To */
	sip_header.write_function(&sip_header, "To: <sip:%s@%s:5060>\r\n", callee_id_number, globals.local_ipv4_str);

	/* Call-ID */
	sip_header.write_function(&sip_header, "Call-ID: %s\r\n", session_uuid);

	/* CSeq */
	sip_header.write_function(&sip_header, "CSeq: 1 %s\r\n", method);

	/* Contact */
	sip_header.write_function(&sip_header, "Contact: sip:freeswitch@%s:5061\r\n", globals.local_ipv4_str);

	/* Max-Forwards */
	sip_header.write_function(&sip_header, "Max-Forwards: 70\r\n", method);

	/* Subject */
	sip_header.write_function(&sip_header, "Subject: %s %s recording of %s\r\n", 
					status == FS_OREKA_START ? "BEGIN": "END",
					type == FS_OREKA_READ ? "RX" : "TX", caller_id_name);

	/* Add any custom extra headers */
	for (ei = extra_headers->headers;
	     ei;
	     ei = ei->next) {
		const char *name = ei->name;
		char *value = ei->value;
		if (!strncasecmp(name, SIP_OREKA_HEADER_PREFIX, SIP_OREKA_HEADER_PREFIX_LEN)) {
			const char *hname = name +  SIP_OREKA_HEADER_PREFIX_LEN;
			sip_header.write_function(&sip_header, "%s: %s\r\n", hname, value);
			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Adding custom oreka SIP header %s: %s\n", hname, value);
		}
	}

	if (status == FS_OREKA_START) {
		/* Content-Type */
		sip_header.write_function(&sip_header, "Content-Type: application/sdp\r\n");

	}

	/* Content-Length */
	sip_header.write_function(&sip_header, "Content-Length: %d\r\n", sdp.data_len);

	udp_packet.write_function(&udp_packet, "%s\r\n%s\n", sip_header.data, sdp.data);

	oreka_write_udp(oreka, &udp_packet);

done:
	if (sip_header.data) {
		free(sip_header.data);
	}

	if (sdp.data) {
		free(sdp.data);
	}

	if (udp_packet.data) {
		free(udp_packet.data);
	}

	if (status == FS_OREKA_STOP) {
		oreka_destroy(oreka);
	}

	return rc;
}
Exemple #10
0
static void *SWITCH_THREAD_FUNC api_exec(switch_thread_t *thread, void *obj)
{
	switch_bool_t r = SWITCH_TRUE;
	struct api_command_struct *acs = (struct api_command_struct *) obj;
	switch_stream_handle_t stream = { 0 };
	char *reply, *freply = NULL;
	switch_status_t status;

	if (!acs) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Internal error.\n");
		return NULL;
	}

	if (!acs->listener || !acs->listener->rwlock || switch_thread_rwlock_tryrdlock(acs->listener->rwlock) != SWITCH_STATUS_SUCCESS) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error! cannot get read lock.\n");
		goto done;
	}

	SWITCH_STANDARD_STREAM(stream);

	if ((status = switch_api_execute(acs->api_cmd, acs->arg, NULL, &stream)) == SWITCH_STATUS_SUCCESS) {
		reply = stream.data;
	} else {
		freply = switch_mprintf("%s: Command not found!\n", acs->api_cmd);
		reply = freply;
		r = SWITCH_FALSE;
	}

	if (!reply) {
		reply = "Command returned no output!";
		r = SWITCH_FALSE;
	}

	if (*reply == '-')
		r = SWITCH_FALSE;

	if (acs->bg) {
		switch_event_t *event;

		if (switch_event_create(&event, SWITCH_EVENT_BACKGROUND_JOB) == SWITCH_STATUS_SUCCESS) {
			ei_x_buff ebuf;

			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", acs->uuid_str);
			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command", acs->api_cmd);

			ei_x_new_with_version(&ebuf);

			if (acs->arg) {
				switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Command-Arg", acs->arg);
			}

			switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-Successful", r ? "true" : "false");
			switch_event_add_body(event, "%s", reply);

			switch_event_fire(&event);

			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending bgapi reply to %s\n", acs->pid.node);

			ei_x_encode_tuple_header(&ebuf, 3);

			if (r)
				ei_x_encode_atom(&ebuf, "bgok");
			else
				ei_x_encode_atom(&ebuf, "bgerror");

			_ei_x_encode_string(&ebuf, acs->uuid_str);
			_ei_x_encode_string(&ebuf, reply);

			switch_mutex_lock(acs->listener->sock_mutex);
			ei_send(acs->listener->sockfd, &acs->pid, ebuf.buff, ebuf.index);
			switch_mutex_unlock(acs->listener->sock_mutex);
#ifdef EI_DEBUG
			ei_x_print_msg(&ebuf, &acs->pid, 1);
#endif

			ei_x_free(&ebuf);
		}
	} else {
		ei_x_buff rbuf;
		ei_x_new_with_version(&rbuf);
		ei_x_encode_tuple_header(&rbuf, 2);

		if (!strlen(reply)) {
			reply = "Command returned no output!";
			r = SWITCH_FALSE;
		}

		if (r) {
			ei_x_encode_atom(&rbuf, "ok");
		} else {
			ei_x_encode_atom(&rbuf, "error");
		}

		_ei_x_encode_string(&rbuf, reply);


		switch_mutex_lock(acs->listener->sock_mutex);
		ei_send(acs->listener->sockfd, &acs->pid, rbuf.buff, rbuf.index);
		switch_mutex_unlock(acs->listener->sock_mutex);
#ifdef EI_DEBUG
		ei_x_print_msg(&rbuf, &acs->pid, 1);
#endif

		ei_x_free(&rbuf);
	}

	switch_safe_free(stream.data);
	switch_safe_free(freply);

	if (acs->listener->rwlock) {
		switch_thread_rwlock_unlock(acs->listener->rwlock);
	}

  done:
	if (acs->bg) {
		switch_memory_pool_t *pool = acs->pool;
		acs = NULL;
		switch_core_destroy_memory_pool(&pool);
		pool = NULL;
	}
	return NULL;

}
Exemple #11
0
static int lua_parse_and_execute(lua_State * L, char *input_code)
{
	int error = 0;

	if (zstr(input_code)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No code to execute!\n");
		return 1;
	}

	while(input_code && (*input_code == ' ' || *input_code == '\n' || *input_code == '\r')) input_code++;
	
	if (*input_code == '~') {
		char *buff = input_code + 1;
		error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 0, 0);	//lua_pcall(L, 0, 0, 0);
	} else if (!strncasecmp(input_code, "#!/lua", 6)) {
		char *buff = input_code + 6;
		error = luaL_loadbuffer(L, buff, strlen(buff), "line") || docall(L, 0, 0, 0);	//lua_pcall(L, 0, 0, 0);
	} else {
		char *args = strchr(input_code, ' ');
		if (args) {
			char *code = NULL;
			int x, argc;
			char *argv[128] = { 0 };
			*args++ = '\0';

			if ((argc = switch_separate_string(args, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
				switch_stream_handle_t stream = { 0 };
				SWITCH_STANDARD_STREAM(stream);

				stream.write_function(&stream, " argv = {[0]='%y', ", input_code);
				for (x = 0; x < argc; x++) {
					stream.write_function(&stream, "'%y'%s", argv[x], x == argc - 1 ? "" : ", ");
				}
				stream.write_function(&stream, " };");
				code = (char *) stream.data;
			} else {
				code = switch_mprintf("argv = {[0]='%s'};", input_code);
			}

			if (code) {
				error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 0, 0);
				switch_safe_free(code);
			}
		} else {
			// Force empty argv table
			char *code = NULL;
			code = switch_mprintf("argv = {[0]='%s'};", input_code);
			error = luaL_loadbuffer(L, code, strlen(code), "line") || docall(L, 0, 0, 0);
			switch_safe_free(code);
		}

		if (!error) {
			char *file = input_code, *fdup = NULL;

			if (!switch_is_file_path(file)) {
				fdup = switch_mprintf("%s/%s", SWITCH_GLOBAL_dirs.script_dir, file);
				switch_assert(fdup);
				file = fdup;
			}
			error = luaL_loadfile(L, file) || docall(L, 0, 0, 0);
			switch_safe_free(fdup);
		}
	}

	if (error) {
		const char *err = lua_tostring(L, -1);
		if (!zstr(err)) {
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", err);
		}
		lua_pop(L, 1);			/* pop error message from the stack */
	}

	return error;
}
Exemple #12
0
static int perl_parse_and_execute(PerlInterpreter * my_perl, char *input_code, char *setup_code)
{
	int error = 0;

	if (zstr(input_code)) {
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No code to execute!\n");
		return -1;
	}

	if (setup_code) {
		error = Perl_safe_eval(my_perl, setup_code);
		if (error) {
			return error;
		}
	}

	if (*input_code == '~') {
		char *buff = input_code + 1;
		error = Perl_safe_eval(my_perl, buff);
	} else {
		char *args = strchr(input_code, ' ');
		if (args) {
			char *code = NULL;
			int x, argc;
			char *argv[128] = { 0 };
			*args++ = '\0';

			if ((argc = switch_separate_string(args, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) {
				switch_stream_handle_t stream = { 0 };
				SWITCH_STANDARD_STREAM(stream);

				stream.write_function(&stream, " @ARGV = ( ");
				for (x = 0; x < argc; x++) {
					stream.write_function(&stream, "'%s'%s", argv[x], x == argc - 1 ? "" : ", ");
				}
				stream.write_function(&stream, " );");
				code = stream.data;
			} else {
				code = switch_mprintf("ARGV = ();");
			}

			if (code) {
				error = Perl_safe_eval(my_perl, code);
				switch_safe_free(code);
			}
		}
		if (!error) {
			char *file = input_code;
			char *err;

			if (!switch_is_file_path(file)) {
				file = switch_mprintf("require '%s/%s';", SWITCH_GLOBAL_dirs.script_dir, file);
				switch_assert(file);
			} else {
				file = switch_mprintf("require '%s';", file);
				switch_assert(file);
			}

			error = Perl_safe_eval(my_perl, file);
			switch_safe_free(file);
		}
	}

	return error;
}
Exemple #13
0
void * SWITCH_THREAD_FUNC mod_amqp_command_thread(switch_thread_t *thread, void *data)
{
	mod_amqp_command_profile_t *profile = (mod_amqp_command_profile_t *) data;

	while (profile->running) {
		amqp_queue_declare_ok_t *recv_queue;
		amqp_bytes_t queueName = { 0, NULL };

		/* Ensure we have an AMQP connection */
		if (!profile->conn_active) {
			switch_status_t status;
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Amqp no connection- reconnecting...\n");

			status = mod_amqp_connection_open(profile->conn_root, &(profile->conn_active), profile->name, profile->custom_attr);
			if ( status	!= SWITCH_STATUS_SUCCESS ) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile[%s] failed to connect with code(%d), sleeping for %dms\n",
								  profile->name, status, profile->reconnect_interval_ms);
				switch_sleep(profile->reconnect_interval_ms * 1000);
				continue;
			}

			/* Check if exchange already exists */ 
			amqp_exchange_declare(profile->conn_active->state, 1,
								  amqp_cstring_bytes(profile->exchange),
								  amqp_cstring_bytes("topic"),
								  0, /* passive */
								  1, /* durable */
								  amqp_empty_table);

			if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Checking for command exchange")) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile[%s] failed to create missing command exchange", profile->name);
				continue;
			}

			/* Ensure we have a queue */
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Creating command queue");
			recv_queue = amqp_queue_declare(profile->conn_active->state, // state
											1,                           // channel
											profile->queue ? amqp_cstring_bytes(profile->queue) : amqp_empty_bytes, // queue name
											0, 0,                        // passive, durable
											0, 1,                        // exclusive, auto-delete
											amqp_empty_table);           // args

			if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Declaring queue")) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Profile[%s] failed to connect with code(%d), sleeping for %dms\n",
								  profile->name, status, profile->reconnect_interval_ms);
				switch_sleep(profile->reconnect_interval_ms * 1000);
				continue;
			}

			if (queueName.bytes) {
				amqp_bytes_free(queueName);
			}

			queueName = amqp_bytes_malloc_dup(recv_queue->queue);

			if (!queueName.bytes) {
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Out of memory while copying queue name");
				break;
			}

			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Created command queue %.*s", (int)queueName.len, (char *)queueName.bytes);
			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Binding command queue to exchange %s", profile->exchange);

			/* Bind the queue to the exchange */
			amqp_queue_bind(profile->conn_active->state,                   // state
							1,                                             // channel
							queueName,                                     // queue
							amqp_cstring_bytes(profile->exchange),         // exchange
							amqp_cstring_bytes(profile->binding_key),      // routing key
							amqp_empty_table);                             // args

			if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Binding queue")) {
				mod_amqp_connection_close(profile->conn_active);
				profile->conn_active = NULL;
				switch_sleep(profile->reconnect_interval_ms * 1000);
				continue;
			}

			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Amqp reconnect successful- connected\n");
			continue;
		}

		// Start a command
		amqp_basic_consume(profile->conn_active->state,     // state
						   1,                               // channel
						   queueName,                       // queue
						   amqp_empty_bytes,                // command tag
						   0, 1, 0,                         // no_local, no_ack, exclusive
						   amqp_empty_table);               // args

		if (mod_amqp_log_if_amqp_error(amqp_get_rpc_reply(profile->conn_active->state), "Creating a command")) {
			mod_amqp_connection_close(profile->conn_active);
			profile->conn_active = NULL;
			switch_sleep(profile->reconnect_interval_ms * 1000);
			continue;
		}

		while (profile->running && profile->conn_active) {
			amqp_rpc_reply_t res;
			amqp_envelope_t envelope;
			struct timeval timeout = {0};
			char command[1024];
			enum ECommandFormat {
				COMMAND_FORMAT_UNKNOWN,
				COMMAND_FORMAT_PLAINTEXT
			} commandFormat = COMMAND_FORMAT_PLAINTEXT;
			char *fs_resp_exchange = NULL, *fs_resp_key = NULL;

			amqp_maybe_release_buffers(profile->conn_active->state);

			timeout.tv_usec = 500 * 1000;
			res = amqp_consume_message(profile->conn_active->state, &envelope, &timeout, 0);

			if (res.reply_type == AMQP_RESPONSE_LIBRARY_EXCEPTION) {
				if (res.library_error == AMQP_STATUS_UNEXPECTED_STATE) {
					/* Unexpected frame. Discard it then continue */
					amqp_frame_t decoded_frame;
					amqp_simple_wait_frame(profile->conn_active->state, &decoded_frame);
				}

				if (res.library_error == AMQP_STATUS_SOCKET_ERROR) {
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A socket error occurred. Tearing down and reconnecting\n");
					break;
				}

				if (res.library_error == AMQP_STATUS_CONNECTION_CLOSED) {
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "AMQP connection was closed. Tearing down and reconnecting\n");
					break;
				}

				if (res.library_error == AMQP_STATUS_TCP_ERROR) {
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "A TCP error occurred. Tearing down and reconnecting\n");
					break;
				}

				if (res.library_error == AMQP_STATUS_TIMEOUT) {
					// nop
				}

				/* Try consuming again */
				continue;
			}

			if (res.reply_type != AMQP_RESPONSE_NORMAL) {
				break;
			}

			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Delivery:%u, exchange:%.*s routingkey:%.*s\n",
							  (unsigned) envelope.delivery_tag, (int) envelope.exchange.len, (char *) envelope.exchange.bytes,
							  (int) envelope.routing_key.len, (char *) envelope.routing_key.bytes);

			if (envelope.message.properties._flags & AMQP_BASIC_CONTENT_TYPE_FLAG) {

				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Content-type: %.*s\n",
								  (int) envelope.message.properties.content_type.len, (char *) envelope.message.properties.content_type.bytes);

				if (strncasecmp("text/plain", envelope.message.properties.content_type.bytes, strlen("text/plain")) == 0) {
					commandFormat = COMMAND_FORMAT_PLAINTEXT;
				} else {
					commandFormat = COMMAND_FORMAT_UNKNOWN;
				}
			}

			if (envelope.message.properties.headers.num_entries) {
				int x = 0;

				for ( x = 0; x < envelope.message.properties.headers.num_entries; x++) {
					char *header_key = (char *)envelope.message.properties.headers.entries[x].key.bytes;
					char *header_value = (char *)envelope.message.properties.headers.entries[x].value.value.bytes.bytes;
					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "AMQP message custom header key[%s] value[%s]\n", header_key, header_value);

					if ( !strncmp(header_key, "x-fs-api-resp-exchange", 22)) {
						fs_resp_exchange = header_value;
					} else if (!strncmp(header_key, "x-fs-api-resp-key", 17)) {
						fs_resp_key = header_value;
					} else {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring unrecognized event header [%s]\n", header_key);
					}
				}
			}

			if (commandFormat == COMMAND_FORMAT_PLAINTEXT) {
				switch_stream_handle_t stream = { 0 }; /* Collects the command output */

				/* Convert amqp bytes to c-string */
				snprintf(command, sizeof(command), "%.*s", (int) envelope.message.body.len, (char *) envelope.message.body.bytes);

				/* Execute the command */
				switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Executing: %s\n", command);

				SWITCH_STANDARD_STREAM(stream);

				if ( fs_resp_exchange && fs_resp_key ) {
					switch_status_t status = switch_console_execute(command, 0, &stream);
					mod_amqp_command_response(profile, command, stream, fs_resp_exchange, fs_resp_key, status);
				} else {
					if (switch_console_execute(command, 0, &stream) != SWITCH_STATUS_SUCCESS) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Remote command failed:\n%s\n", (char *) stream.data);
					} else {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote command succeeded:\n%s\n", (char *) stream.data);
					}
				}
				switch_safe_free(stream.data);
			}

			/* Tidy up */
			amqp_destroy_envelope(&envelope);
		}

		amqp_bytes_free(queueName);
		queueName.bytes = NULL;

		mod_amqp_connection_close(profile->conn_active);
		profile->conn_active = NULL;

		if (profile->running) {
			/* We'll reconnect, but sleep to avoid hammering resources */
			switch_sleep(500);
		}
	}

	/* Terminate the thread */
	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Command listener thread stopped\n");
	switch_thread_exit(thread, SWITCH_STATUS_SUCCESS);
	return NULL;
}
switch_status_t chat_send(switch_event_t *message_event)
{
	char name[512] = "", *p, *lbuf = NULL;
	conference_obj_t *conference = NULL;
	switch_stream_handle_t stream = { 0 };
	const char *proto;
	const char *from;
	const char *to;
	//const char *subject;
	const char *body;
	//const char *type;
	const char *hint;

	proto = switch_event_get_header(message_event, "proto");
	from = switch_event_get_header(message_event, "from");
	to = switch_event_get_header(message_event, "to");
	body = switch_event_get_body(message_event);
	hint = switch_event_get_header(message_event, "hint");


	if ((p = strchr(to, '+'))) {
		to = ++p;
	}

	if (!body) {
		return SWITCH_STATUS_SUCCESS;
	}

	if ((p = strchr(to, '@'))) {
		switch_copy_string(name, to, ++p - to);
	} else {
		switch_copy_string(name, to, sizeof(name));
	}

	if (!(conference = conference_find(name, NULL))) {
		switch_core_chat_send_args(proto, CONF_CHAT_PROTO, to, hint && strchr(hint, '/') ? hint : from, "",
								   "Conference not active.", NULL, NULL, SWITCH_FALSE);
		return SWITCH_STATUS_FALSE;
	}

	SWITCH_STANDARD_STREAM(stream);

	if (body != NULL && (lbuf = strdup(body))) {
		/* special case list */
		if (conference->broadcast_chat_messages) {
			conference_event_chat_message_broadcast(conference, message_event);
		} else if (switch_stristr("list", lbuf)) {
			conference_list_pretty(conference, &stream);
			/* provide help */
		} else {
			return SWITCH_STATUS_SUCCESS;
		}
	}

	switch_safe_free(lbuf);

	if (!conference->broadcast_chat_messages) {
		switch_core_chat_send_args(proto, CONF_CHAT_PROTO, to, hint && strchr(hint, '/') ? hint : from, "", stream.data, NULL, NULL, SWITCH_FALSE);
	}

	switch_safe_free(stream.data);
	switch_thread_rwlock_unlock(conference->rwlock);

	return SWITCH_STATUS_SUCCESS;
}
void conference_event_mod_channel_handler(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id)
{
	cJSON *data, *addobj = NULL;
	const char *action = NULL;
	char *value = NULL;
	cJSON *jid = 0;
	char *conference_name = strdup(event_channel + 15);
	char cid[32] = "";
	char *p;
	switch_stream_handle_t stream = { 0 };
	char *exec = NULL;
	cJSON *msg, *jdata, *jvalue;
	char *argv[10] = {0};
	int argc = 0;

	if (conference_name && (p = strchr(conference_name, '@'))) {
		*p = '\0';
	}

	if ((data = cJSON_GetObjectItem(json, "data"))) {
		action = cJSON_GetObjectCstr(data, "command");
		if ((jid = cJSON_GetObjectItem(data, "id"))) {
			if (jid->valueint) {
				switch_snprintf(cid, sizeof(cid), "%d", jid->valueint);
			} else if (!zstr(jid->valuestring)) {
				switch_snprintf(cid, sizeof(cid), "%s", jid->valuestring);
			}
		}

		if ((jvalue = cJSON_GetObjectItem(data, "value"))) {

			if (jvalue->type == cJSON_Array) {
				int i;
				argc = cJSON_GetArraySize(jvalue);
				if (argc > 10) argc = 10;

				for (i = 0; i < argc; i++) {
					cJSON *str = cJSON_GetArrayItem(jvalue, i);
					if (str->type == cJSON_String) {
						argv[i] = str->valuestring;
					}
				}
			} else if (jvalue->type == cJSON_String) {
				value = jvalue->valuestring;
				argv[argc++] = value;
			}
		}
	}

	switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "conf %s CMD %s [%s] %s\n", conference_name, key, action, cid);

	if (zstr(action)) {
		goto end;
	}

	SWITCH_STANDARD_STREAM(stream);

	if (!strcasecmp(action, "kick")) {
		exec = switch_mprintf("%s %s %s", conference_name, action, cid);
	} else if (!strcasecmp(action, "mute") ||
		!strcasecmp(action, "unmute") ||
		!strcasecmp(action, "tmute") ||
		!strcasecmp(action, "vmute") ||
		!strcasecmp(action, "unvmute") ||
		!strcasecmp(action, "tvmute")) {
		if (argv[0]) {
		  exec = switch_mprintf("%s %s %s %s", conference_name, action, cid, argv[0]);
		} else {
		  exec = switch_mprintf("%s %s %s", conference_name, action, cid);
		}
	} else if (!strcasecmp(action, "volume_in") ||
			   !strcasecmp(action, "volume_out") ||
			   !strcasecmp(action, "vid-res-id") ||
			   !strcasecmp(action, "vid-floor") ||
			   !strcasecmp(action, "vid-layer") ||
			   !strcasecmp(action, "vid-canvas") ||
			   !strcasecmp(action, "vid-watching-canvas") ||
			   !strcasecmp(action, "vid-banner")) {
		exec = switch_mprintf("%s %s %s %s", conference_name, action, cid, argv[0]);
	} else if (!strcasecmp(action, "play") || !strcasecmp(action, "stop")) {
		exec = switch_mprintf("%s %s %s", conference_name, action, argv[0]);
	} else if (!strcasecmp(action, "recording") || !strcasecmp(action, "vid-layout") || !strcasecmp(action, "vid-write-png")) {

		if (!argv[1]) {
			argv[1] = "all";
		}

		exec = switch_mprintf("%s %s %s %s", conference_name, action, argv[0], argv[1]);

	} else if (!strcasecmp(action, "transfer")) {
		conference_member_t *member;
		conference_obj_t *conference;

		if (cid[0] == '\0') {
			stream.write_function(&stream, "-ERR Call transfer requires id");
			goto end;
		}

		exec = switch_mprintf("%s %s %s", argv[0], switch_str_nil(argv[1]), switch_str_nil(argv[2]));
		stream.write_function(&stream, "+OK Call transferred to %s", argv[0]);

		if ((conference = conference_find(conference_name, NULL))) {
			if ((member = conference_member_get(conference, atoi(cid)))) {
				switch_ivr_session_transfer(member->session, argv[0], argv[1], argv[2]);
				switch_thread_rwlock_unlock(member->rwlock);
			}
			switch_thread_rwlock_unlock(conference->rwlock);
		}
		goto end;
	} else if (!strcasecmp(action, "list-videoLayouts")) {
		switch_hash_index_t *hi;
		void *val;
		const void *vvar;
		cJSON *array = cJSON_CreateArray();
		conference_obj_t *conference = NULL;
		if ((conference = conference_find(conference_name, NULL))) {
			switch_mutex_lock(conference_globals.setup_mutex);
			if (conference->layout_hash) {
				for (hi = switch_core_hash_first(conference->layout_hash); hi; hi = switch_core_hash_next(&hi)) {
					switch_core_hash_this(hi, &vvar, NULL, &val);
					cJSON_AddItemToArray(array, cJSON_CreateString((char *)vvar));
				}
			}

			if (conference->layout_group_hash) {
				for (hi = switch_core_hash_first(conference->layout_group_hash); hi; hi = switch_core_hash_next(&hi)) {
					char *name;
					switch_core_hash_this(hi, &vvar, NULL, &val);
					name = switch_mprintf("group:%s", (char *)vvar);
					cJSON_AddItemToArray(array, cJSON_CreateString(name));
					free(name);
				}
			}

			switch_mutex_unlock(conference_globals.setup_mutex);
			switch_thread_rwlock_unlock(conference->rwlock);
		}
		addobj = array;
	}

	if (exec) {
		conference_api_main_real(exec, NULL, &stream);
	}

 end:

	msg = cJSON_CreateObject();
	jdata = json_add_child_obj(msg, "data", NULL);

	cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(event_channel));
	cJSON_AddItemToObject(jdata, "action", cJSON_CreateString("response"));

	if (addobj) {
		cJSON_AddItemToObject(jdata, "conf-command", cJSON_CreateString(action));
		cJSON_AddItemToObject(jdata, "response", cJSON_CreateString("OK"));
		cJSON_AddItemToObject(jdata, "responseData", addobj);
	} else if (exec) {
		cJSON_AddItemToObject(jdata, "conf-command", cJSON_CreateString(exec));
		cJSON_AddItemToObject(jdata, "response", cJSON_CreateString((char *)stream.data));
		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT,"RES [%s][%s]\n", exec, (char *)stream.data);
	} else {
		cJSON_AddItemToObject(jdata, "error", cJSON_CreateString("Invalid Command"));
	}

	switch_event_channel_broadcast(event_channel, &msg, __FILE__, conference_globals.event_channel_id);


	switch_safe_free(stream.data);
	switch_safe_free(exec);

	switch_safe_free(conference_name);

}