int ast_custom_payload_sipinfo_decode(struct ast_custom_payload *pl,
	struct ast_variable **headers,
	char **content_type,
	char **content,
	char **useragent_filter)
{
	struct custom_sipinfo *sipinfo;
	struct ast_variable *cur = NULL;
	char *data;
	int i;

	*headers = NULL;
	*content_type = NULL;
	*content = NULL;
	*useragent_filter = NULL;

	if (pl->type != AST_CUSTOM_SIP_INFO) {
		return -1;
	}

	sipinfo = (struct custom_sipinfo *) pl->data;
	data = sipinfo->data;
	for (i = 0; i < sipinfo->num_headers; i++) {
		const char *name;
		const char *value;

		name = data;
		data += strlen(name) + 1;
		value = data;
		data += strlen(value) + 1;

		if (*headers) {
			if ((cur->next = ast_variable_new(name, value, ""))) {
				cur = cur->next;
			}
		} else {
			*headers = cur = ast_variable_new(name, value, "");
		}
	}

	if (sipinfo->content_present) {
		*content_type = ast_strdup(data);
		data += strlen(data) + 1;
		*content = ast_strdup(data);
		data += strlen(data) + 1;
	}

	if (sipinfo->useragent_filter_present) {
		*useragent_filter = ast_strdup(data);
	}
	return 0;
}
Example #2
0
int ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
{
	struct ast_json_iter *it_json_var;

	*variables = NULL;

	for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
		 it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
		struct ast_variable *new_var;
		const char *key = ast_json_object_iter_key(it_json_var);

		if (ast_strlen_zero(key)) {
			continue;
		}

		new_var = ast_variable_new(key,
		                           ast_json_string_get(ast_json_object_iter_value(it_json_var)),
		                           "");
		if (!new_var) {
			ast_variables_destroy(*variables);
			*variables = NULL;
			return -1;
		}

		ast_variable_list_append(variables, new_var);
	}

	return 0;
}
Example #3
0
static int localnet_to_vl(const void *obj, struct ast_variable **fields)
{
	const struct ast_sip_transport *transport = obj;
	char str[MAX_OBJECT_FIELD];
	struct ast_variable *head = NULL;
	struct ast_ha *ha;
	RAII_VAR(struct ast_sip_transport_state *, state, find_state_by_transport(transport), ao2_cleanup);

	if (!state) {
		return -1;
	}

	for (ha = state->localnet; ha; ha = ha->next) {
		const char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
		snprintf(str, MAX_OBJECT_FIELD, "%s%s/%s", ha->sense == AST_SENSE_ALLOW ? "!" : "",
			addr, ast_sockaddr_stringify_addr(&ha->netmask));

		ast_variable_list_append(&head, ast_variable_new("local_net", str, ""));
	}

	if (head) {
		*fields = head;
	}

	return 0;
}
Example #4
0
static int json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
{
    struct ast_variable *current = NULL;
    struct ast_json_iter *it_json_var;

    for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
            it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
        struct ast_variable *new_var;

        new_var = ast_variable_new(ast_json_object_iter_key(it_json_var),
                                   ast_json_string_get(ast_json_object_iter_value(it_json_var)),
                                   "");
        if (!new_var) {
            ast_variables_destroy(*variables);
            *variables = NULL;
            return 1;
        }

        if (!current) {
            *variables = new_var;
            current = *variables;
        } else {
            current->next = new_var;
            current = new_var;
        }
    }

    return 0;
}
Example #5
0
static int on_aor_update_endpoint_state(void *obj, void *arg, int flags)
{
	struct ast_sip_aor *aor = obj;
	struct ao2_container *endpoints;
	RAII_VAR(struct ast_variable *, var, NULL, ast_variables_destroy);
	const char *aor_name = ast_sorcery_object_get_id(aor);
	char *aor_like;

	if (ast_strlen_zero(aor_name)) {
		return -1;
	}

	if (aor->permanent_contacts && ((int)(aor->qualify_frequency * 1000)) <= 0) {
		aor_like = ast_alloca(strlen(aor_name) + 3);
		sprintf(aor_like, "%%%s%%", aor_name);
		var = ast_variable_new("aors LIKE", aor_like, "");
		if (!var) {
			return -1;
		}
		endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
			"endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var);

		if (endpoints) {
		    /*
		     * Because aors are a string list, we have to use a pattern match but since a simple
		     * pattern match could return an endpoint that has an aor of "aaabccc" when searching
		     * for "abc", we still have to iterate over them to find an exact aor match.
		     */
		    ao2_callback(endpoints, 0, aor_update_endpoint_state, (char *)aor_name);
		    ao2_ref(endpoints, -1);
		}
	}

	return 0;
}
Example #6
0
static void qualify_and_schedule_all(void)
{
	struct ast_variable *var = ast_variable_new("qualify_frequency >", "0", "");
	struct ao2_container *aors;
	struct ao2_container *contacts;

	if (!var) {
		return;
	}
	aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
		"aor", AST_RETRIEVE_FLAG_MULTIPLE, var);

	ao2_callback(sched_qualifies, OBJ_NODATA | OBJ_MULTIPLE | OBJ_UNLINK, unschedule_all_cb, NULL);

	if (aors) {
		ao2_callback(aors, OBJ_NODATA, qualify_and_schedule_all_cb, NULL);
		ao2_ref(aors, -1);
	}

	contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
		"contact", AST_RETRIEVE_FLAG_MULTIPLE, var);
	if (contacts) {
		ao2_callback(contacts, OBJ_NODATA, qualify_and_schedule_cb_without_aor, NULL);
		ao2_ref(contacts, -1);
	}

	ast_variables_destroy(var);

}
static struct ast_config *realtime_directory(char *context)
{
	struct ast_config *cfg;
	struct ast_config *rtdata;
	struct ast_category *cat;
	struct ast_variable *var;
	char *mailbox;
	char *fullname;
	char *hidefromdir;
	char tmp[100];

	/* Load flat file config. */
	cfg = ast_config_load(VOICEMAIL_CONFIG);

	if (!cfg) {
		/* Loading config failed. */
		ast_log(LOG_WARNING, "Loading config failed.\n");
		return NULL;
	}

	/* Get realtime entries, categorized by their mailbox number
	   and present in the requested context */
	rtdata = ast_load_realtime_multientry("voicemail", "mailbox LIKE", "%", "context", context, NULL);

	/* if there are no results, just return the entries from the config file */
	if (!rtdata)
		return cfg;

	/* Does the context exist within the config file? If not, make one */
	cat = ast_category_get(cfg, context);
	if (!cat) {
		cat = ast_category_new(context);
		if (!cat) {
			ast_log(LOG_WARNING, "Out of memory\n");
			ast_config_destroy(cfg);
			return NULL;
		}
		ast_category_append(cfg, cat);
	}

	mailbox = ast_category_browse(rtdata, NULL);
	while (mailbox) {
		fullname = ast_variable_retrieve(rtdata, mailbox, "fullname");
		hidefromdir = ast_variable_retrieve(rtdata, mailbox, "hidefromdir");
		snprintf(tmp, sizeof(tmp), "no-password,%s,hidefromdir=%s",
			 fullname ? fullname : "",
			 hidefromdir ? hidefromdir : "no");
		var = ast_variable_new(mailbox, tmp);
		if (var)
			ast_variable_append(cat, var);
		else
			ast_log(LOG_WARNING, "Out of memory adding mailbox '%s'\n", mailbox);
		mailbox = ast_category_browse(rtdata, mailbox);
	}
	ast_config_destroy(rtdata);

	return cfg;
}
Example #8
0
static int contact_to_var_list(void *object, void *arg, int flags)
{
	struct ast_sip_contact_wrapper *wrapper = object;
	struct ast_variable **var = arg;

	ast_variable_list_append(&*var, ast_variable_new("contact", wrapper->contact->uri, ""));

	return 0;
}
Example #9
0
/*!
 * \brief Verifies a user event header/value pair
 *
 * \param user_event which user event to check
 * \param header The header to verify
 * \param value The value read from the event
 *
 * \retval -1 on error or evaluation failure
 * \retval 0 if match not needed or success
 */
static int verify_user_event_fields(int user_event, const char *header, const char *value)
{
	struct ast_variable *current;
	struct ast_variable *expected;
	regex_t regexbuf;
	int error;

	if (user_event >= AST_VECTOR_SIZE(&expected_user_event_fields)) {
		return -1;
	}

	expected = AST_VECTOR_GET(&expected_user_event_fields, user_event);
	if (!expected) {
		return -1;
	}

	for (current = expected; current; current = current->next) {
		struct ast_variable *bad_header;

		if (strcmp(current->name, header)) {
			continue;
		}

		error = regcomp(&regexbuf, current->value, REG_EXTENDED | REG_NOSUB);
		if (error) {
			char error_buf[128];
			regerror(error, &regexbuf, error_buf, sizeof(error_buf));
			ast_log(LOG_ERROR, "Failed to compile regex '%s' for header check '%s': %s\n",
				current->value, current->name, error_buf);
			return -1;
		}

		if (!regexec(&regexbuf, value, 0, NULL, 0)) {
			regfree(&regexbuf);
			return 0;
		}

		bad_header = ast_variable_new(header, value, __FILE__);
		if (bad_header) {
			struct ast_variable *bad_headers_head = NULL;

			if (user_event < AST_VECTOR_SIZE(&bad_headers)) {
				bad_headers_head = AST_VECTOR_GET(&bad_headers, user_event);
			}
			ast_variable_list_append(&bad_headers_head, bad_header);
			AST_VECTOR_INSERT(&bad_headers, user_event, bad_headers_head);
		}
		regfree(&regexbuf);
		return -1;
	}

	return 0;
}
Example #10
0
static void update_all_unqualified_endpoints(void)
{
	struct ao2_container *aors;
	struct ao2_container *contacts;
	RAII_VAR(struct ast_variable *, var_aor, NULL, ast_variables_destroy);
	RAII_VAR(struct ast_variable *, var_contact, NULL, ast_variables_destroy);
	RAII_VAR(char *, time_now, NULL, ast_free);
	struct timeval tv = ast_tvnow();

	if (!(var_aor = ast_variable_new("contact !=", "", ""))) {
		return;
	}
	if (!(var_aor->next = ast_variable_new("qualify_frequency <=", "0", ""))) {
		return;
	}

	if (ast_asprintf(&time_now, "%ld", tv.tv_sec) == -1) {
		return;
	}
	if (!(var_contact = ast_variable_new("expiration_time >", time_now, ""))) {
		return;
	}
	if (!(var_contact->next = ast_variable_new("qualify_frequency <=", "0", ""))) {
		return;
	}

	aors = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
		"aor", AST_RETRIEVE_FLAG_MULTIPLE, var_aor);
	if (aors) {
		ao2_callback(aors, OBJ_NODATA, on_aor_update_endpoint_state, NULL);
		ao2_ref(aors, -1);
	}

	contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
		"contact", AST_RETRIEVE_FLAG_MULTIPLE, var_contact);
	if (contacts) {
		ao2_callback(contacts, OBJ_NODATA, contact_update_endpoint_state, NULL);
		ao2_ref(contacts, -1);
	}
}
static int realtime_sorcery_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
{
	struct ast_category *object, *found;

	if (!(found = ast_category_get(realtime_objects, entity, NULL))) {
		return 0;
	} else if (!(object = ast_category_new(entity, "", 0))) {
		return -1;
	}

	ast_category_delete(realtime_objects, found);
	ast_variable_append(object, ast_variables_dup((struct ast_variable*)fields));
	ast_variable_append(object, ast_variable_new(keyfield, entity, ""));
	ast_category_append(realtime_objects, object);

	return 1;
}
static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object)
{
	const char *family = data;
	RAII_VAR(struct ast_variable *, fields, ast_sorcery_objectset_create(sorcery, object), ast_variables_destroy);
	struct ast_variable *id = ast_variable_new(UUID_FIELD, ast_sorcery_object_get_id(object), "");

	if (!fields || !id) {
		ast_variables_destroy(id);
		return -1;
	}

	/* Place the identifier at the front for sanity sake */
	id->next = fields;
	fields = id;

	return (ast_store_realtime_fields(family, fields) <= 0) ? -1 : 0;
}
Example #13
0
enum ast_json_to_ast_vars_code ast_json_to_ast_variables(struct ast_json *json_variables, struct ast_variable **variables)
{
	struct ast_json_iter *it_json_var;

	*variables = NULL;

	for (it_json_var = ast_json_object_iter(json_variables); it_json_var;
		it_json_var = ast_json_object_iter_next(json_variables, it_json_var)) {
		struct ast_variable *new_var;
		const char *key = ast_json_object_iter_key(it_json_var);
		const char *value;
		struct ast_json *json_value;

		if (ast_strlen_zero(key)) {
			continue;
		}

		json_value = ast_json_object_iter_value(it_json_var);
		if (ast_json_typeof(json_value) != AST_JSON_STRING) {
			/* Error: Only strings allowed */
			ast_variables_destroy(*variables);
			*variables = NULL;
			return AST_JSON_TO_AST_VARS_CODE_INVALID_TYPE;
		}
		value = ast_json_string_get(json_value);
		/* Should never be NULL.  Otherwise, how could it be a string type? */
		ast_assert(value != NULL);
		if (!value) {
			/* To be safe. */
			continue;
		}
		new_var = ast_variable_new(key, value, "");
		if (!new_var) {
			/* Error: OOM */
			ast_variables_destroy(*variables);
			*variables = NULL;
			return AST_JSON_TO_AST_VARS_CODE_OOM;
		}

		ast_variable_list_append(variables, new_var);
	}

	return AST_JSON_TO_AST_VARS_CODE_SUCCESS;
}
static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex)
{
	char field[strlen(UUID_FIELD) + 6], value[strlen(regex) + 3];
	RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);

	/* The realtime API provides no direct ability to do regex so for now we support a limited subset using pattern matching */
	snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
	if (regex[0] == '^') {
		snprintf(value, sizeof(value), "%s%%", regex + 1);
	} else {
		snprintf(value, sizeof(value), "%%%s%%", regex);
	}

	if (!(fields = ast_variable_new(field, value, ""))) {
		return;
	}

	sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
}
Example #15
0
/*! \brief Helper function which converts a json object to a sorcery object set */
static struct ast_variable *sorcery_json_to_objectset(struct ast_json *json)
{
	struct ast_json_iter *field;
	struct ast_variable *objset = NULL;

	for (field = ast_json_object_iter(json); field; field = ast_json_object_iter_next(json, field)) {
		struct ast_json *value = ast_json_object_iter_value(field);
		struct ast_variable *variable = ast_variable_new(ast_json_object_iter_key(field), ast_json_string_get(value), "");

		if (!variable) {
			ast_variables_destroy(objset);
			return NULL;
		}

		variable->next = objset;
		objset = variable;
	}

	return objset;
}
Example #16
0
/*!
 * \brief Build ast_config struct from above definitions
 *
 * \retval NULL Failed to build the config
 * \retval non-NULL An ast_config struct populated with data
 */
static struct ast_config *build_cfg(void)
{
	struct ast_config *cfg;
	struct association *cat_iter;
	struct pair *var_iter;
	size_t i;
	size_t j;

	cfg = ast_config_new();
	if (!cfg) {
		goto fail;
	}

	for (i = 0; i < ARRAY_LEN(categories); ++i) {
		struct ast_category *cat;
		cat_iter = &categories[i];

		cat = ast_category_new(cat_iter->category, "", 999999);
		if (!cat) {
			goto fail;
		}
		ast_category_append(cfg, cat);

		for (j = 0; j < ARRAY_LEN(cat_iter->vars); ++j) {
			struct ast_variable *var;
			var_iter = &cat_iter->vars[j];

			var = ast_variable_new(var_iter->name, var_iter->val, "");
			if (!var) {
				goto fail;
			}
			ast_variable_append(cat, var);
		}
	}

	return cfg;

fail:
	ast_config_destroy(cfg);
	return NULL;
}
static void sorcery_realtime_retrieve_multiple(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const struct ast_variable *fields)
{
	const char *family = data;
	RAII_VAR(struct ast_config *, rows, NULL, ast_config_destroy);
	RAII_VAR(struct ast_variable *, all, NULL, ast_variables_destroy);
	struct ast_category *row = NULL;

	if (!fields) {
		char field[strlen(UUID_FIELD) + 6], value[2];

		/* If no fields have been specified we want all rows, so trick realtime into doing it */
		snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
		snprintf(value, sizeof(value), "%%");

		if (!(all = ast_variable_new(field, value, ""))) {
			return;
		}

		fields = all;
	}

	if (!(rows = ast_load_realtime_multientry_fields(family, fields))) {
		return;
	}

	while ((row = ast_category_browse_filtered(rows, NULL, row, NULL))) {
		struct ast_variable *objectset = ast_category_detach_variables(row);
		RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy);
		RAII_VAR(void *, object, NULL, ao2_cleanup);

		objectset = sorcery_realtime_filter_objectset(objectset, &id, sorcery, type);

		if (id && (object = ast_sorcery_alloc(sorcery, type, id->value)) && !ast_sorcery_objectset_apply(sorcery, object, objectset)) {
			ao2_link(objects, object);
		}

		ast_variables_destroy(objectset);
	}
}
static struct ast_variable *parse_cookies(char *cookies)
{
	char *cur;
	struct ast_variable *vars = NULL, *var;

	/* Skip Cookie: */
	cookies += 8;

	while ((cur = strsep(&cookies, ";"))) {
		char *name, *val;
		
		name = val = cur;
		strsep(&val, "=");

		if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
			continue;
		}

		name = ast_strip(name);
		val = ast_strip_quoted(val, "\"", "\"");

		if (ast_strlen_zero(name) || ast_strlen_zero(val)) {
			continue;
		}

		if (option_debug) {
			ast_log(LOG_DEBUG, "mmm ... cookie!  Name: '%s'  Value: '%s'\n", name, val);
		}

		var = ast_variable_new(name, val);
		var->next = vars;
		vars = var;
	}

	return vars;
}
Example #19
0
/*!
 * \internal
 * \brief Find an endpoint associated with the given contact.
 */
static struct ast_sip_endpoint *find_an_endpoint(struct ast_sip_contact *contact)
{
	struct ao2_container *endpoints;
	struct ast_sip_endpoint *endpoint;
	struct ast_variable *var;
	char *aor = ast_alloca(strlen(contact->aor) + 3);

	sprintf(aor, "%%%s%%", contact->aor);
	var = ast_variable_new("aors LIKE", aor, "");
	endpoints = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(),
		"endpoint", AST_RETRIEVE_FLAG_MULTIPLE, var);

	ast_variables_destroy(var);

	/*
	 * Because aors are a string list, we have to use a pattern match but since a simple
	 * pattern match could return an endpoint that has an aor of "aaabccc" when searching
	 * for "abc", we still have to iterate over them to find an exact aor match.
	 */
	endpoint = ao2_callback(endpoints, 0, on_endpoint, (char *)contact->aor);
	ao2_ref(endpoints, -1);

	return endpoint;
}
static struct ast_config *config_curl(const char *url, const char *unused, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl, const char *who_asked)
{
	struct ast_str *query, *buffer;
	char buf1[200];
	char *stringp, *line, *pair, *key;
	int last_cat_metric = -1, cat_metric = -1;
	struct ast_category *cat = NULL;
	char *cur_cat = "";
	char *category = "", *var_name = "", *var_val = "";
	struct ast_flags loader_flags = { 0 };

	if (!ast_custom_function_find("CURL")) {
		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
		return NULL;
	}

	if (!(query = ast_str_thread_get(&query_buf, 100))) {
		return NULL;
	}

	if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
		return NULL;
	}

	ast_uri_encode(file, buf1, sizeof(buf1), ast_uri_http);
	ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);

	/* Do the CURL query */
	ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));

	/* Line oriented output */
	stringp = ast_str_buffer(buffer);
	cat = ast_config_get_current_category(cfg);

	while ((line = strsep(&stringp, "\r\n"))) {
		if (ast_strlen_zero(line)) {
			continue;
		}

		while ((pair = strsep(&line, "&"))) {
			key = strsep(&pair, "=");
			ast_uri_decode(key, ast_uri_http);
			if (pair) {
				ast_uri_decode(pair, ast_uri_http);
			}

			if (!strcasecmp(key, "category")) {
				category = S_OR(pair, "");
			} else if (!strcasecmp(key, "var_name")) {
				var_name = S_OR(pair, "");
			} else if (!strcasecmp(key, "var_val")) {
				var_val = S_OR(pair, "");
			} else if (!strcasecmp(key, "cat_metric")) {
				cat_metric = pair ? atoi(pair) : 0;
			}
		}

		if (!strcmp(var_name, "#include")) {
			if (!ast_config_internal_load(var_val, cfg, loader_flags, "", who_asked))
				return NULL;
		}

		if (!cat || strcmp(category, cur_cat) || last_cat_metric != cat_metric) {
			if (!(cat = ast_category_new(category, "", 99999)))
				break;
			cur_cat = category;
			last_cat_metric = cat_metric;
			ast_category_append(cfg, cat);
		}
		ast_variable_append(cat, ast_variable_new(var_name, var_val, ""));
	}

	return cfg;
}
Example #21
0
void ast_ari_invoke(struct ast_tcptls_session_instance *ser,
                    const char *uri, enum ast_http_method method,
                    struct ast_variable *get_params, struct ast_variable *headers,
                    struct ast_ari_response *response)
{
    RAII_VAR(struct stasis_rest_handlers *, root, NULL, ao2_cleanup);
    struct stasis_rest_handlers *handler;
    RAII_VAR(struct ast_variable *, path_vars, NULL, ast_variables_destroy);
    char *path = ast_strdupa(uri);
    char *path_segment;
    stasis_rest_callback callback;

    root = handler = get_root_handler();
    ast_assert(root != NULL);

    while ((path_segment = strsep(&path, "/")) && (strlen(path_segment) > 0)) {
        struct stasis_rest_handlers *found_handler = NULL;
        int i;
        ast_uri_decode(path_segment, ast_uri_http_legacy);
        ast_debug(3, "Finding handler for %s\n", path_segment);
        for (i = 0; found_handler == NULL && i < handler->num_children; ++i) {
            struct stasis_rest_handlers *child = handler->children[i];

            ast_debug(3, "  Checking %s\n", child->path_segment);
            if (child->is_wildcard) {
                /* Record the path variable */
                struct ast_variable *path_var = ast_variable_new(child->path_segment, path_segment, __FILE__);
                path_var->next = path_vars;
                path_vars = path_var;
                found_handler = child;
            } else if (strcmp(child->path_segment, path_segment) == 0) {
                found_handler = child;
            }
        }

        if (found_handler == NULL) {
            /* resource not found */
            ast_debug(3, "  Handler not found\n");
            ast_ari_response_error(
                response, 404, "Not Found",
                "Resource not found");
            return;
        } else {
            ast_debug(3, "  Got it!\n");
            handler = found_handler;
        }
    }

    ast_assert(handler != NULL);
    if (method == AST_HTTP_OPTIONS) {
        handle_options(handler, headers, response);
        return;
    }

    if (method < 0 || method >= AST_HTTP_MAX_METHOD) {
        add_allow_header(handler, response);
        ast_ari_response_error(
            response, 405, "Method Not Allowed",
            "Invalid method");
        return;
    }

    if (handler->ws_server && method == AST_HTTP_GET) {
        /* WebSocket! */
        ari_handle_websocket(handler->ws_server, ser, uri, method,
                             get_params, headers);
        /* Since the WebSocket code handles the connection, we shouldn't
         * do anything else; setting no_response */
        response->no_response = 1;
        return;
    }

    callback = handler->callbacks[method];
    if (callback == NULL) {
        add_allow_header(handler, response);
        ast_ari_response_error(
            response, 405, "Method Not Allowed",
            "Invalid method");
        return;
    }

    callback(ser, get_params, path_vars, headers, response);
    if (response->message == NULL && response->response_code == 0) {
        /* Really should not happen */
        ast_log(LOG_ERROR, "ARI %s %s not implemented\n",
                ast_get_http_method(method), uri);
        ast_ari_response_error(
            response, 501, "Not Implemented",
            "Method not implemented");
    }
}
static struct ast_config *config_sqlite(const char *database, const char *table, const char *file, struct ast_config *cfg)
{
	struct ast_variable *new_v, *v;
	struct ast_category *cur_cat;
	char ttable[ARRAY_SIZE];
	int configured = 0, res = 0;
	sqlite3_stmt *stmt = NULL;;
	int cat_metric=0, last_cat_metric=0;
	char sql[ARRAY_SIZE];
	char last[ARRAY_SIZE] = "";
	char path[ARRAY_SIZE];
	sqlite3 *db;
	int running=0;
	int i=0;
	struct ast_config *config;


	/* if the data was not passed from extconfig.conf then get it from sqlite.conf */
	if(!database || ast_strlen_zero(database)) {
		if (!file || !strcmp (file, "res_sqlite.conf"))
			return NULL; // cant configure myself with myself !

		config = ast_config_load ("res_sqlite.conf");
		if (config) {
			for (v = ast_variable_browse (config, "config"); v; v = v->next) {
				if (!strcmp (v->name, "table")) {
					strncpy (ttable, v->value, sizeof (ttable));
					configured++;
				} else if (!strcmp (v->name, "dbfile")) {
					pick_path(v->value,path,ARRAY_SIZE);
					configured++;
				}
			}
			ast_config_destroy (config);
		}
	} else {
		pick_path((char *)database,path,ARRAY_SIZE);
		strncpy (ttable, table, sizeof (ttable));
		configured = 2;
	}

	if (configured < 2)
		return NULL;


	db=open_db(path);
	if (!db)
		return NULL;

	sprintf (sql, "select * from %s where filename='%s' and commented=0 order by filename,cat_metric desc,var_metric asc,id", ttable, file);
	res = sqlite3_prepare(db,sql,0,&stmt,0);

	if (res) {
		ast_log (LOG_WARNING, "SQL select error [%s]!\n[%s]\n\n",sqlite3_errmsg(db), sql);
		return NULL;
	}

	cur_cat = ast_config_get_current_category(cfg);

	/*
	  0 id int
	  1 cat_metric int not null default 0,
	  2 var_metric int not null default 0,
	  3 commented int not null default 0,
	  4 filename varchar(128) not null,
	  5 category varchar(128) not null default 'default',
	  6 var_name varchar(128) not null,
	  7 var_val varchar(128) not null
	*/
	
	running = 1;
	while (running) {
		res = sqlite3_step(stmt);
		running = 1;
		switch( res ){
		case SQLITE_DONE:	running = 0 ; break;
		case SQLITE_BUSY:	sleep(2); running = 2; break ;
		case SQLITE_ERROR:	running = 0; break;
		case SQLITE_MISUSE: running = 0; break;
		case SQLITE_ROW:	
		default: 
			break;
		}	
		if (!running)
			break;
		
		if (running == 2)
			continue;

		if(option_verbose > 4)
			for(i=0;i<8;i++){
				ast_verbose(VERBOSE_PREFIX_3"SQLite Config: %d=%s\n",i,sqlite3_column_text(stmt,i));
			}
		
		if (strcmp (last, sqlite3_column_text(stmt,5)) || last_cat_metric != cat_metric) {
			cur_cat = ast_category_new((char *)sqlite3_column_text(stmt,5));
			if (!cur_cat) {
				ast_log(LOG_WARNING, "Out of memory!\n");
				break;
			}
			strcpy (last, sqlite3_column_text(stmt,5));
			last_cat_metric	= cat_metric;
			ast_category_append(cfg, cur_cat);
		}
		new_v = ast_variable_new ((char *)sqlite3_column_text(stmt,6), (char *)sqlite3_column_text(stmt,7));
		ast_variable_append(cur_cat, new_v);
	}
	
	if ((sqlite3_finalize(stmt))) 
		ast_log(LOG_ERROR,"ERROR: %s\n",sqlite3_errmsg(db));

	return cfg;
}
static char *handle_uri(struct sockaddr_in *sin, char *uri, int *status, 
	char **title, int *contentlength, struct ast_variable **cookies, 
	unsigned int *static_content)
{
	char *c;
	char *turi;
	char *params;
	char *var;
	char *val;
	struct ast_http_uri *urih=NULL;
	int len;
	struct ast_variable *vars=NULL, *v, *prev = NULL;
	
	
	params = strchr(uri, '?');
	if (params) {
		*params = '\0';
		params++;
		while ((var = strsep(&params, "&"))) {
			val = strchr(var, '=');
			if (val) {
				*val = '\0';
				val++;
				ast_uri_decode(val);
			} else 
				val = "";
			ast_uri_decode(var);
			if ((v = ast_variable_new(var, val))) {
				if (vars)
					prev->next = v;
				else
					vars = v;
				prev = v;
			}
		}
	}
	if (prev)
		prev->next = *cookies;
	else
		vars = *cookies;
	*cookies = NULL;
	ast_uri_decode(uri);
	if (!strncasecmp(uri, prefix, prefix_len)) {
		uri += prefix_len;
		if (!*uri || (*uri == '/')) {
			if (*uri == '/')
				uri++;
			ast_rwlock_rdlock(&uris_lock);
			urih = uris;
			while(urih) {
				len = strlen(urih->uri);
				if (!strncasecmp(urih->uri, uri, len)) {
					if (!uri[len] || uri[len] == '/') {
						turi = uri + len;
						if (*turi == '/')
							turi++;
						if (!*turi || urih->has_subtree) {
							uri = turi;
							break;
						}
					}
				}
				urih = urih->next;
			}
			if (!urih)
				ast_rwlock_unlock(&uris_lock);
		}
	}
	if (urih) {
		if (urih->static_content)
			*static_content = 1;
		c = urih->callback(sin, uri, vars, status, title, contentlength);
		ast_rwlock_unlock(&uris_lock);
	} else if (ast_strlen_zero(uri) && ast_strlen_zero(prefix)) {
		/* Special case: If no prefix, and no URI, send to /static/index.html */
		c = ast_http_error(302, "Moved Temporarily", "Location: /static/index.html\r\n", "Redirecting to /static/index.html.");
		*status = 302;
		*title = strdup("Moved Temporarily");
	} else {
		c = ast_http_error(404, "Not Found", NULL, "The requested URL was not found on this server.");
		*status = 404;
		*title = strdup("Not Found");
	}
	ast_variables_destroy(vars);
	return c;
}
Example #24
0
static struct ast_variable *realtime_pgsql(const char *database, const char *table, va_list ap)
{
	PGresult *result = NULL;
	int num_rows = 0;
	char sql[256];
	char *stringp;
	char *chunk;
	char *op;
	const char *newparam, *newval;
	struct ast_variable *var = NULL, *prev = NULL;

	if (!table) {
		ast_log(LOG_WARNING, "Postgresql RealTime: No table specified.\n");
		return NULL;
	}

	/* Get the first parameter and first value in our list of passed paramater/value pairs */
	newparam = va_arg(ap, const char *);
	newval = va_arg(ap, const char *);
	if (!newparam || !newval) {
		ast_log(LOG_WARNING,
				"Postgresql RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
		if (pgsqlConn) {
			PQfinish(pgsqlConn);
			pgsqlConn = NULL;
		};
		return NULL;
	}

	/* Create the first part of the query using the first parameter/value pairs we just extracted
	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
	op = strchr(newparam, ' ') ? "" : " =";

	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
			 newval);
	while ((newparam = va_arg(ap, const char *))) {
		newval = va_arg(ap, const char *);
		if (!strchr(newparam, ' '))
			op = " =";
		else
			op = "";
		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
				 op, newval);
	}
	va_end(ap);

	/* We now have our complete statement; Lets connect to the server and execute it. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	}

	if (!(result = PQexec(pgsqlConn, sql))) {
		ast_log(LOG_WARNING,
				"Postgresql RealTime: Failed to query database. Check debug for more info.\n");
		ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
		ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
				PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"Postgresql RealTime: Failed to query database. Check debug for more info.\n");
			ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
			ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
					PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return NULL;
		}
	}

	ast_log(LOG_DEBUG, "1Postgresql RealTime: Result=%p Query: %s\n", result, sql);

	if ((num_rows = PQntuples(result)) > 0) {
		int i = 0;
		int rowIndex = 0;
		int numFields = PQnfields(result);
		char **fieldnames = NULL;

		ast_log(LOG_DEBUG, "Postgresql RealTime: Found %d rows.\n", num_rows);

		if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
			ast_mutex_unlock(&pgsql_lock);
			PQclear(result);
			return NULL;
		}
		for (i = 0; i < numFields; i++)
			fieldnames[i] = PQfname(result, i);
		for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
			for (i = 0; i < numFields; i++) {
				stringp = PQgetvalue(result, rowIndex, i);
				while (stringp) {
					chunk = strsep(&stringp, ";");
					if (chunk && !ast_strlen_zero(ast_strip(chunk))) {
						if (prev) {
							prev->next = ast_variable_new(fieldnames[i], chunk);
							if (prev->next) {
								prev = prev->next;
							}
						} else {
							prev = var = ast_variable_new(fieldnames[i], chunk);
						}
					}
				}
			}
		}
		free(fieldnames);
	} else {
		ast_log(LOG_WARNING,
				"Postgresql RealTime: Could not find any rows in table %s.\n", table);
	}

	ast_mutex_unlock(&pgsql_lock);
	PQclear(result);

	return var;
}
Example #25
0
static struct ast_config *config_pgsql(const char *database, const char *table,
					   const char *file, struct ast_config *cfg,
					   int withcomments)
{
	PGresult *result = NULL;
	long num_rows;
	struct ast_variable *new_v;
	struct ast_category *cur_cat = NULL;
	char sqlbuf[1024] = "";
	char *sql;
	size_t sqlleft = sizeof(sqlbuf);
	char last[80] = "";
	int last_cat_metric = 0;

	last[0] = '\0';

	if (!file || !strcmp(file, RES_CONFIG_PGSQL_CONF)) {
		ast_log(LOG_WARNING, "Postgresql RealTime: Cannot configure myself.\n");
		return NULL;
	}

	ast_build_string(&sql, &sqlleft, "SELECT category, var_name, var_val, cat_metric FROM %s ", table);
	ast_build_string(&sql, &sqlleft, "WHERE filename='%s' and commented=0", file);
	ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");

	ast_log(LOG_DEBUG, "Postgresql RealTime: Static SQL: %s\n", sqlbuf);

	/* We now have our complete statement; Lets connect to the server and execute it. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	}

	if (!(result = PQexec(pgsqlConn, sqlbuf))) {
		ast_log(LOG_WARNING,
				"Postgresql RealTime: Failed to query database. Check debug for more info.\n");
		ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
		ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s\n",
				PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"Postgresql RealTime: Failed to query database. Check debug for more info.\n");
			ast_log(LOG_DEBUG, "Postgresql RealTime: Query: %s\n", sql);
			ast_log(LOG_DEBUG, "Postgresql RealTime: Query Failed because: %s (%s)\n",
					PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return NULL;
		}
	}

	if ((num_rows = PQntuples(result)) > 0) {
		int rowIndex = 0;

		ast_log(LOG_DEBUG, "Postgresql RealTime: Found %ld rows.\n", num_rows);

		for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
			char *field_category = PQgetvalue(result, rowIndex, 0);
			char *field_var_name = PQgetvalue(result, rowIndex, 1);
			char *field_var_val = PQgetvalue(result, rowIndex, 2);
			char *field_cat_metric = PQgetvalue(result, rowIndex, 3);
			if (!strcmp(field_var_name, "#include")) {
				if (!ast_config_internal_load(field_var_val, cfg, 0)) {
					PQclear(result);
					ast_mutex_unlock(&pgsql_lock);
					return NULL;
				}
				continue;
			}

			if (strcmp(last, field_category) || last_cat_metric != atoi(field_cat_metric)) {
				cur_cat = ast_category_new(field_category);
				if (!cur_cat)
					break;
				strcpy(last, field_category);
				last_cat_metric = atoi(field_cat_metric);
				ast_category_append(cfg, cur_cat);
			}
			new_v = ast_variable_new(field_var_name, field_var_val);
			ast_variable_append(cur_cat, new_v);
		}
	} else {
		ast_log(LOG_WARNING,
				"Postgresql RealTime: Could not find config '%s' in database.\n", file);
	}

	PQclear(result);
	ast_mutex_unlock(&pgsql_lock);

	return cfg;
}
Example #26
0
static int apply_outgoing(struct outgoing *o, char *fn, FILE *f)
{
	char buf[256];
	char *c, *c2;
	int lineno = 0;
	struct ast_variable *var;

	while(fgets(buf, sizeof(buf), f)) {
		lineno++;
		/* Trim comments */
		c = buf;
		while ((c = strchr(c, '#'))) {
			if ((c == buf) || (*(c-1) == ' ') || (*(c-1) == '\t'))
				*c = '\0';
			else
				c++;
		}

		c = buf;
		while ((c = strchr(c, ';'))) {
			if ((c > buf) && (c[-1] == '\\')) {
				memmove(c - 1, c, strlen(c) + 1);
				c++;
			} else {
				*c = '\0';
				break;
			}
		}

		/* Trim trailing white space */
		while(!ast_strlen_zero(buf) && buf[strlen(buf) - 1] < 33)
			buf[strlen(buf) - 1] = '\0';
		if (!ast_strlen_zero(buf)) {
			c = strchr(buf, ':');
			if (c) {
				*c = '\0';
				c++;
				while ((*c) && (*c < 33))
					c++;
#if 0
				printf("'%s' is '%s' at line %d\n", buf, c, lineno);
#endif
				if (!strcasecmp(buf, "channel")) {
					ast_copy_string(o->tech, c, sizeof(o->tech));
					if ((c2 = strchr(o->tech, '/'))) {
						*c2 = '\0';
						c2++;
						ast_copy_string(o->dest, c2, sizeof(o->dest));
					} else {
						ast_log(LOG_NOTICE, "Channel should be in form Tech/Dest at line %d of %s\n", lineno, fn);
						o->tech[0] = '\0';
					}
				} else if (!strcasecmp(buf, "callerid")) {
					ast_callerid_split(c, o->cid_name, sizeof(o->cid_name), o->cid_num, sizeof(o->cid_num));
				} else if (!strcasecmp(buf, "application")) {
					ast_copy_string(o->app, c, sizeof(o->app));
				} else if (!strcasecmp(buf, "data")) {
					ast_copy_string(o->data, c, sizeof(o->data));
				} else if (!strcasecmp(buf, "maxretries")) {
					if (sscanf(c, "%d", &o->maxretries) != 1) {
						ast_log(LOG_WARNING, "Invalid max retries at line %d of %s\n", lineno, fn);
						o->maxretries = 0;
					}
				} else if (!strcasecmp(buf, "context")) {
					ast_copy_string(o->context, c, sizeof(o->context));
				} else if (!strcasecmp(buf, "extension")) {
					ast_copy_string(o->exten, c, sizeof(o->exten));
				} else if (!strcasecmp(buf, "priority")) {
					if ((sscanf(c, "%d", &o->priority) != 1) || (o->priority < 1)) {
						ast_log(LOG_WARNING, "Invalid priority at line %d of %s\n", lineno, fn);
						o->priority = 1;
					}
				} else if (!strcasecmp(buf, "retrytime")) {
					if ((sscanf(c, "%d", &o->retrytime) != 1) || (o->retrytime < 1)) {
						ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn);
						o->retrytime = 300;
					}
				} else if (!strcasecmp(buf, "waittime")) {
					if ((sscanf(c, "%d", &o->waittime) != 1) || (o->waittime < 1)) {
						ast_log(LOG_WARNING, "Invalid retrytime at line %d of %s\n", lineno, fn);
						o->waittime = 45;
					}
				} else if (!strcasecmp(buf, "retry")) {
					o->retries++;
				} else if (!strcasecmp(buf, "startretry")) {
					if (sscanf(c, "%ld", &o->callingpid) != 1) {
						ast_log(LOG_WARNING, "Unable to retrieve calling PID!\n");
						o->callingpid = 0;
					}
				} else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) {
					o->callingpid = 0;
					o->retries++;
				} else if (!strcasecmp(buf, "delayedretry")) {
				} else if (!strcasecmp(buf, "setvar") || !strcasecmp(buf, "set")) {
					c2 = c;
					strsep(&c2, "=");
					if (c2) {
						var = ast_variable_new(c, c2);
						if (var) {
							var->next = o->vars;
							o->vars = var;
						}
					} else
						ast_log(LOG_WARNING, "Malformed \"%s\" argument.  Should be \"%s: variable=value\"\n", buf, buf);
				} else if (!strcasecmp(buf, "account")) {
					ast_copy_string(o->account, c, sizeof(o->account));
				} else if (!strcasecmp(buf, "alwaysdelete")) {
					ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ALWAYS_DELETE);
				} else if (!strcasecmp(buf, "archive")) {
					ast_set2_flag(&o->options, ast_true(c), SPOOL_FLAG_ARCHIVE);
				} else {
					ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn);
				}
			} else
				ast_log(LOG_NOTICE, "Syntax error at line %d of %s\n", lineno, fn);
		}
	}
	ast_copy_string(o->fn, fn, sizeof(o->fn));
	if (ast_strlen_zero(o->tech) || ast_strlen_zero(o->dest) || (ast_strlen_zero(o->app) && ast_strlen_zero(o->exten))) {
		ast_log(LOG_WARNING, "At least one of app or extension must be specified, along with tech and dest in file %s\n", fn);
		return -1;
	}
	return 0;
}
/*!
 * \brief Excute an Select query and return ast_config list
 * \param url
 * \param unused
 * \param fields list containing one or more field/operator/value set.
 *
 * \retval struct ast_config pointer on success
 * \retval NULL on failure
*/
static struct ast_config *realtime_multi_curl(const char *url, const char *unused, const struct ast_variable *fields)
{
	struct ast_str *query, *buffer;
	char buf1[256], buf2[256];
	const struct ast_variable *field;
	char *stringp, *line, *pair, *key, *initfield = NULL;
	int start = 1;
	struct ast_variable *var = NULL;
	struct ast_config *cfg = NULL;
	struct ast_category *cat = NULL;

	if (!ast_custom_function_find("CURL")) {
		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
		return NULL;
	}

	if (!(query = ast_str_thread_get(&query_buf, 16))) {
		return NULL;
	}

	if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
		return NULL;
	}

	ast_str_set(&query, 0, "${CURL(%s/multi,", url);

	for (field = fields; field; field = field->next) {
		if (start) {
			char *op;
			initfield = ast_strdupa(field->name);
			if ((op = strchr(initfield, ' ')))
				*op = '\0';
		}
		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
		ast_str_append(&query, 0, "%s%s=%s", !start ? "&" : "", buf1, buf2);
		start = 0;
	}

	ast_str_append(&query, 0, ")}");

	/* Do the CURL query */
	ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));

	if (!(cfg = ast_config_new())) {
		return NULL;
	}

	/* Line oriented output */
	stringp = ast_str_buffer(buffer);
	while ((line = strsep(&stringp, "\r\n"))) {
		if (ast_strlen_zero(line)) {
			continue;
		}

		if (!(cat = ast_category_new("", "", 99999))) {
			continue;
		}

		while ((pair = strsep(&line, "&"))) {
			key = strsep(&pair, "=");
			ast_uri_decode(key, ast_uri_http);
			if (pair) {
				ast_uri_decode(pair, ast_uri_http);
			}

			if (!strcasecmp(key, initfield) && pair) {
				ast_category_rename(cat, pair);
			}

			if (!ast_strlen_zero(key)) {
				var = ast_variable_new(key, S_OR(pair, ""), "");
				ast_variable_append(cat, var);
			}
		}
		ast_category_append(cfg, cat);
	}

	return cfg;
}
Example #28
0
void ast_ari_asterisk_update_object(struct ast_variable *headers, struct ast_ari_asterisk_update_object_args *args, struct ast_ari_response *response)
{
	RAII_VAR(struct ast_sorcery *, sorcery, NULL, ast_sorcery_unref);
	RAII_VAR(struct ast_sorcery_object_type *, object_type, NULL, ao2_cleanup);
	RAII_VAR(void *, sorcery_obj, NULL, ao2_cleanup);
	struct ast_json *fields;
	struct ast_variable *update_set = NULL;
	int created = 0;

	sorcery = ast_sorcery_retrieve_by_module_name(args->config_class);
	if (!sorcery) {
		ast_ari_response_error(
			response, 404, "Not Found",
			"configClass '%s' not found",
			args->config_class);
		return;
	}

	object_type = ast_sorcery_get_object_type(sorcery, args->object_type);
	if (!object_type) {
		ast_ari_response_error(
			response, 404, "Not Found",
			"objectType '%s' not found",
			args->object_type);
		return;
	}

	sorcery_obj = ast_sorcery_retrieve_by_id(sorcery, args->object_type, args->id);
	if (!sorcery_obj) {
		ast_debug(5, "Sorcery object '%s' does not exist; creating it\n", args->id);
		sorcery_obj = ast_sorcery_alloc(sorcery, args->object_type, args->id);
		if (!sorcery_obj) {
			ast_ari_response_alloc_failed(response);
			return;
		}

		created = 1;
	} else {
		void *copy;

		copy = ast_sorcery_copy(sorcery, sorcery_obj);
		if (!copy) {
			ast_ari_response_alloc_failed(response);
			return;
		}

		ao2_ref(sorcery_obj, -1);
		sorcery_obj = copy;
	}

	fields = ast_json_object_get(args->fields, "fields");
	if (!fields && !created) {
		/* Whoops. We need data. */
		ast_ari_response_error(
			response, 400, "Bad request",
			"Fields must be provided to update object '%s'",
			args->id);
		return;
	} else if (fields) {
		size_t i;

		for (i = 0; i < ast_json_array_size(fields); i++) {
			struct ast_variable *new_var;
			struct ast_json *json_value = ast_json_array_get(fields, i);

			if (!json_value) {
				continue;
			}

			new_var = ast_variable_new(
				ast_json_string_get(ast_json_object_get(json_value, "attribute")),
				ast_json_string_get(ast_json_object_get(json_value, "value")),
				"");
			if (!new_var) {
				ast_variables_destroy(update_set);
				ast_ari_response_alloc_failed(response);
				return;
			}
			ast_variable_list_append(&update_set, new_var);
		}
	}

	/* APPLY! Note that a NULL update_set is fine (and necessary), as it
	 * will force validation on a newly created object.
	 */
	if (ast_sorcery_objectset_apply(sorcery, sorcery_obj, update_set)) {
		ast_variables_destroy(update_set);
		ast_ari_response_error(
			response, 400, "Bad request",
			"%s of object '%s' failed field value validation",
			created ? "Creation" : "Update",
			args->id);
		return;
	}

	ast_variables_destroy(update_set);

	if (created) {
		if (ast_sorcery_create(sorcery, sorcery_obj)) {
			ast_ari_response_error(
				response, 403, "Forbidden",
				"Cannot create sorcery objects of type '%s'",
				args->object_type);
			return;
		}
	} else {
		if (ast_sorcery_update(sorcery, sorcery_obj)) {
			ast_ari_response_error(
				response, 403, "Forbidden",
				"Cannot update sorcery objects of type '%s'",
				args->object_type);
			return;
		}
	}

	return_sorcery_object(sorcery, sorcery_obj, response);
}
static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, va_list ap)
{
	PGresult *result = NULL;
	int num_rows = 0, pgerror;
	char sql[256], escapebuf[513];
	const char *initfield = NULL;
	char *stringp;
	char *chunk;
	char *op;
	const char *newparam, *newval;
	struct ast_variable *var = NULL;
	struct ast_config *cfg = NULL;
	struct ast_category *cat = NULL;

	if (!table) {
		ast_log(LOG_WARNING, "PostgreSQL RealTime: No table specified.\n");
		return NULL;
	}

	if (!(cfg = ast_config_new()))
		return NULL;

	/* Get the first parameter and first value in our list of passed paramater/value pairs */
	newparam = va_arg(ap, const char *);
	newval = va_arg(ap, const char *);
	if (!newparam || !newval) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
		if (pgsqlConn) {
			PQfinish(pgsqlConn);
			pgsqlConn = NULL;
		};
		return NULL;
	}

	initfield = ast_strdupa(newparam);
	if ((op = strchr(initfield, ' '))) {
		*op = '\0';
	}

	/* Create the first part of the query using the first parameter/value pairs we just extracted
	   If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */

	if (!strchr(newparam, ' '))
		op = " =";
	else
		op = "";

	PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
	if (pgerror) {
		ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
		va_end(ap);
		return NULL;
	}

	snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op,
			 escapebuf);
	while ((newparam = va_arg(ap, const char *))) {
		newval = va_arg(ap, const char *);
		if (!strchr(newparam, ' '))
			op = " =";
		else
			op = "";

		PQescapeStringConn(pgsqlConn, escapebuf, newval, (sizeof(escapebuf) - 1) / 2, &pgerror);
		if (pgerror) {
			ast_log(LOG_ERROR, "Postgres detected invalid input: '%s'\n", newval);
			va_end(ap);
			return NULL;
		}

		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s '%s'", newparam,
				 op, escapebuf);
	}

	if (initfield) {
		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
	}

	va_end(ap);

	/* We now have our complete statement; Lets connect to the server and execute it. */
	ast_mutex_lock(&pgsql_lock);
	if (!pgsql_reconnect(database)) {
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	}

	if (!(result = PQexec(pgsqlConn, sql))) {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
		ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
		ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s\n", PQerrorMessage(pgsqlConn));
		ast_mutex_unlock(&pgsql_lock);
		return NULL;
	} else {
		ExecStatusType result_status = PQresultStatus(result);
		if (result_status != PGRES_COMMAND_OK
			&& result_status != PGRES_TUPLES_OK
			&& result_status != PGRES_NONFATAL_ERROR) {
			ast_log(LOG_WARNING,
					"PostgreSQL RealTime: Failed to query database. Check debug for more info.\n");
			ast_debug(1, "PostgreSQL RealTime: Query: %s\n", sql);
			ast_debug(1, "PostgreSQL RealTime: Query Failed because: %s (%s)\n",
						PQresultErrorMessage(result), PQresStatus(result_status));
			ast_mutex_unlock(&pgsql_lock);
			return NULL;
		}
	}

	ast_debug(1, "PostgreSQL RealTime: Result=%p Query: %s\n", result, sql);

	if ((num_rows = PQntuples(result)) > 0) {
		int numFields = PQnfields(result);
		int i = 0;
		int rowIndex = 0;
		char **fieldnames = NULL;

		ast_debug(1, "PostgreSQL RealTime: Found %d rows.\n", num_rows);

		if (!(fieldnames = ast_calloc(1, numFields * sizeof(char *)))) {
			ast_mutex_unlock(&pgsql_lock);
			PQclear(result);
			return NULL;
		}
		for (i = 0; i < numFields; i++)
			fieldnames[i] = PQfname(result, i);

		for (rowIndex = 0; rowIndex < num_rows; rowIndex++) {
			var = NULL;
			if (!(cat = ast_category_new("","",99999)))
				continue;
			for (i = 0; i < numFields; i++) {
				stringp = PQgetvalue(result, rowIndex, i);
				while (stringp) {
					chunk = strsep(&stringp, ";");
					if (!ast_strlen_zero(ast_strip(chunk))) {
						if (initfield && !strcmp(initfield, fieldnames[i])) {
							ast_category_rename(cat, chunk);
						}
						var = ast_variable_new(fieldnames[i], chunk, "");
						ast_variable_append(cat, var);
					}
				}
			}
			ast_category_append(cfg, cat);
		}
		ast_free(fieldnames);
	} else {
		ast_log(LOG_WARNING,
				"PostgreSQL RealTime: Could not find any rows in table %s.\n", table);
	}

	ast_mutex_unlock(&pgsql_lock);
	PQclear(result);

	return cfg;
}
/*!
 * \brief Execute a curl query and return ast_variable list
 * \param url The base URL from which to retrieve data
 * \param unused Not currently used
 * \param fields list containing one or more field/operator/value set.
 *
 * \retval var on success
 * \retval NULL on failure
*/
static struct ast_variable *realtime_curl(const char *url, const char *unused, const struct ast_variable *fields)
{
	struct ast_str *query, *buffer;
	char buf1[256], buf2[256];
	const struct ast_variable *field;
	char *stringp, *pair, *key;
	unsigned int start = 1;
	struct ast_variable *var = NULL, *prev = NULL;

	if (!ast_custom_function_find("CURL")) {
		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
		return NULL;
	}

	if (!(query = ast_str_thread_get(&query_buf, 16))) {
		return NULL;
	}

	if (!(buffer = ast_str_thread_get(&result_buf, 16))) {
		return NULL;
	}

	ast_str_set(&query, 0, "${CURL(%s/single,", url);

	for (field = fields; field; field = field->next) {
		ast_uri_encode(field->name, buf1, sizeof(buf1), ast_uri_http);
		ast_uri_encode(field->value, buf2, sizeof(buf2), ast_uri_http);
		ast_str_append(&query, 0, "%s%s=%s", !start ? "&" : "", buf1, buf2);
		start = 0;
	}

	ast_str_append(&query, 0, ")}");
	ast_str_substitute_variables(&buffer, 0, NULL, ast_str_buffer(query));

	/* Remove any trailing newline characters */
	if ((stringp = strchr(ast_str_buffer(buffer), '\r')) || (stringp = strchr(ast_str_buffer(buffer), '\n'))) {
		*stringp = '\0';
	}

	stringp = ast_str_buffer(buffer);
	while ((pair = strsep(&stringp, "&"))) {
		key = strsep(&pair, "=");
		ast_uri_decode(key, ast_uri_http);
		if (pair) {
			ast_uri_decode(pair, ast_uri_http);
		}

		if (!ast_strlen_zero(key)) {
			if (prev) {
				prev->next = ast_variable_new(key, S_OR(pair, ""), "");
				if (prev->next) {
					prev = prev->next;
				}
			} else {
				prev = var = ast_variable_new(key, S_OR(pair, ""), "");
			}
		}
	}

	return var;
}