summaryrefslogtreecommitdiff
path: root/res
diff options
context:
space:
mode:
authorJoshua Colp <jcolp@digium.com>2013-04-27 12:01:29 +0000
committerJoshua Colp <jcolp@digium.com>2013-04-27 12:01:29 +0000
commit02be50b1ac46febdc65f680dd97448381ec00ef4 (patch)
tree3b18060c3c3c73be045e0d2e69e603622f98e3cf /res
parentc5f1eecb15d312d4286c00d22c00416824e0289a (diff)
Add support for a realtime sorcery module.
This change does the following: 1. Adds the sorcery realtime module 2. Adds unit tests for the sorcery realtime module 3. Changes the realtime core to use an ast_variable list instead of variadic arguments 4. Changes all realtime drivers to accept an ast_variable list Review: https://reviewboard.asterisk.org/r/2424/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@386731 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'res')
-rw-r--r--res/res_config_curl.c132
-rw-r--r--res/res_config_ldap.c125
-rw-r--r--res/res_config_odbc.c228
-rw-r--r--res/res_config_pgsql.c149
-rw-r--r--res/res_config_sqlite3.c82
-rw-r--r--res/res_sorcery_realtime.c252
6 files changed, 564 insertions, 404 deletions
diff --git a/res/res_config_curl.c b/res/res_config_curl.c
index 81ad23467..9dfcb0d9d 100644
--- a/res/res_config_curl.c
+++ b/res/res_config_curl.c
@@ -53,18 +53,18 @@ AST_THREADSTORAGE(result_buf);
* \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 ap list containing one or more field/operator/value set.
+ * \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, va_list ap)
+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 char *newparam, *newval;
+ const struct ast_variable *field;
char *stringp, *pair, *key;
- int i;
+ unsigned int start = 1;
struct ast_variable *var = NULL, *prev = NULL;
if (!ast_custom_function_find("CURL")) {
@@ -82,11 +82,11 @@ static struct ast_variable *realtime_curl(const char *url, const char *unused, v
ast_str_set(&query, 0, "${CURL(%s/single,", url);
- for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
- newval = va_arg(ap, const char *);
- ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
- ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
- ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+ 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, ")}");
@@ -124,18 +124,18 @@ static struct ast_variable *realtime_curl(const char *url, const char *unused, v
* \brief Excute an Select query and return ast_config list
* \param url
* \param unused
- * \param ap list containing one or more field/operator/value set.
+ * \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, va_list ap)
+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 char *newparam, *newval;
+ const struct ast_variable *field;
char *stringp, *line, *pair, *key, *initfield = NULL;
- int i;
+ int start = 1;
struct ast_variable *var = NULL;
struct ast_config *cfg = NULL;
struct ast_category *cat = NULL;
@@ -155,17 +155,17 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
ast_str_set(&query, 0, "${CURL(%s/multi,", url);
- for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
- newval = va_arg(ap, const char *);
- if (i == 0) {
+ for (field = fields; field; field = field->next) {
+ if (start) {
char *op;
- initfield = ast_strdupa(newparam);
+ initfield = ast_strdupa(field->name);
if ((op = strchr(initfield, ' ')))
*op = '\0';
}
- ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
- ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
- ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+ 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, ")}");
@@ -216,7 +216,7 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
* \param unused
* \param keyfield where clause field
* \param lookup value of field for where clause
- * \param ap list containing one or more field/value set(s).
+ * \param fields list containing one or more field/value set(s).
*
* Update a database table, prepare the sql statement using keyfield and lookup
* control the number of records to change. All values to be changed are stored in ap list.
@@ -225,13 +225,13 @@ static struct ast_config *realtime_multi_curl(const char *url, const char *unuse
* \retval number of rows affected
* \retval -1 on failure
*/
-static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
+static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, const struct ast_variable *fields)
{
struct ast_str *query, *buffer;
char buf1[256], buf2[256];
- const char *newparam, *newval;
+ const struct ast_variable *field;
char *stringp;
- int i, rowcount = -1;
+ int start = 1, rowcount = -1;
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");
@@ -250,11 +250,11 @@ static int update_curl(const char *url, const char *unused, const char *keyfield
ast_uri_encode(lookup, buf2, sizeof(buf2), ast_uri_http);
ast_str_set(&query, 0, "${CURL(%s/update?%s=%s,", url, buf1, buf2);
- for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
- newval = va_arg(ap, const char *);
- ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
- ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
- ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+ 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, ")}");
@@ -274,13 +274,14 @@ static int update_curl(const char *url, const char *unused, const char *keyfield
return -1;
}
-static int update2_curl(const char *url, const char *unused, va_list ap)
+static int update2_curl(const char *url, const char *unused, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
{
struct ast_str *query, *buffer;
char buf1[200], buf2[200];
- const char *newparam, *newval;
+ const struct ast_variable *field;
char *stringp;
- int rowcount = -1, lookup = 1, first = 1;
+ unsigned int start = 1;
+ int rowcount = -1;
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");
@@ -296,23 +297,20 @@ static int update2_curl(const char *url, const char *unused, va_list ap)
ast_str_set(&query, 0, "${CURL(%s/update?", url);
- for (;;) {
- if ((newparam = va_arg(ap, const char *)) == SENTINEL) {
- if (lookup) {
- lookup = 0;
- ast_str_append(&query, 0, ",");
- /* Back to the first parameter; we don't need a starting '&' */
- first = 1;
- continue;
- } else {
- break;
- }
- }
- newval = va_arg(ap, const char *);
- ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
- ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
- ast_str_append(&query, 0, "%s%s=%s", first ? "" : "&", buf1, buf2);
- first = 0;
+ for (field = lookup_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, ",");
+ start = 1;
+
+ for (field = update_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, ")}");
@@ -340,7 +338,7 @@ static int update2_curl(const char *url, const char *unused, va_list ap)
* \brief Execute an INSERT query
* \param url
* \param unused
- * \param ap list containing one or more field/value set(s)
+ * \param fields list containing one or more field/value set(s)
*
* Insert a new record into database table, prepare the sql statement.
* All values to be changed are stored in ap list.
@@ -349,13 +347,13 @@ static int update2_curl(const char *url, const char *unused, va_list ap)
* \retval number of rows affected
* \retval -1 on failure
*/
-static int store_curl(const char *url, const char *unused, va_list ap)
+static int store_curl(const char *url, const char *unused, const struct ast_variable *fields)
{
struct ast_str *query, *buffer;
char buf1[256], buf2[256];
- const char *newparam, *newval;
+ const struct ast_variable *field;
char *stringp;
- int i, rowcount = -1;
+ int start = 1, rowcount = -1;
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");
@@ -372,11 +370,11 @@ static int store_curl(const char *url, const char *unused, va_list ap)
ast_str_set(&query, 0, "${CURL(%s/store,", url);
- for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
- newval = va_arg(ap, const char *);
- ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
- ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
- ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+ 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, ")}");
@@ -401,7 +399,7 @@ static int store_curl(const char *url, const char *unused, va_list ap)
* \param unused
* \param keyfield where clause field
* \param lookup value of field for where clause
- * \param ap list containing one or more field/value set(s)
+ * \param fields list containing one or more field/value set(s)
*
* Delete a row from a database table, prepare the sql statement using keyfield and lookup
* control the number of records to change. Additional params to match rows are stored in ap list.
@@ -410,13 +408,13 @@ static int store_curl(const char *url, const char *unused, va_list ap)
* \retval number of rows affected
* \retval -1 on failure
*/
-static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
+static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, const struct ast_variable *fields)
{
struct ast_str *query, *buffer;
char buf1[200], buf2[200];
- const char *newparam, *newval;
+ const struct ast_variable *field;
char *stringp;
- int i, rowcount = -1;
+ int start = 1, rowcount = -1;
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");
@@ -435,11 +433,11 @@ static int destroy_curl(const char *url, const char *unused, const char *keyfiel
ast_uri_encode(lookup, buf2, sizeof(buf2), ast_uri_http);
ast_str_set(&query, 0, "${CURL(%s/destroy,%s=%s&", url, buf1, buf2);
- for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
- newval = va_arg(ap, const char *);
- ast_uri_encode(newparam, buf1, sizeof(buf1), ast_uri_http);
- ast_uri_encode(newval, buf2, sizeof(buf2), ast_uri_http);
- ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+ 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, ")}");
diff --git a/res/res_config_ldap.c b/res/res_config_ldap.c
index b44adf4bc..79dc987eb 100644
--- a/res/res_config_ldap.c
+++ b/res/res_config_ldap.c
@@ -762,14 +762,13 @@ static void append_var_and_value_to_filter(struct ast_str **filter,
* \param entries_count_ptr is a pointer to found entries count (can be NULL)
* \param basedn is the base DN
* \param table_name is the table_name (used dor attribute convertion and additional filter)
- * \param ap contains null terminated list of pairs name/value
+ * \param fields contains list of pairs name/value
*/
static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_ptr,
- const char *basedn, const char *table_name, va_list ap)
+ const char *basedn, const char *table_name, const struct ast_variable *fields)
{
struct ast_variable **vars = NULL;
- const char *newparam = NULL;
- const char *newval = NULL;
+ const struct ast_variable *field = fields;
struct ldap_table_config *table_config = NULL;
char *clean_basedn = cleaned_basedn(NULL, basedn);
struct ast_str *filter = NULL;
@@ -789,11 +788,7 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
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) {
+ if (!field) {
ast_log(LOG_ERROR, "Realtime retrieval requires at least 1 parameter"
" and 1 value to search on.\n");
ast_free(filter);
@@ -834,10 +829,9 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
* If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat
*/
- append_var_and_value_to_filter(&filter, table_config, newparam, newval);
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- append_var_and_value_to_filter(&filter, table_config, newparam, newval);
+ append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
+ while ((field = field->next)) {
+ append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
}
ast_str_append(&filter, 0, ")");
@@ -947,18 +941,42 @@ static struct ast_variable **realtime_ldap_base_ap(unsigned int *entries_count_p
return vars;
}
+static struct ast_variable *realtime_arguments_to_fields(va_list ap)
+{
+ struct ast_variable *fields = NULL;
+ const char *newparam, *newval;
+
+ while ((newparam = va_arg(ap, const char *))) {
+ struct ast_variable *field;
+
+ newval = va_arg(ap, const char *);
+ if (!(field = ast_variable_new(newparam, newval, ""))) {
+ ast_variables_destroy(fields);
+ return NULL;
+ }
+
+ field->next = fields;
+ fields = field;
+ }
+
+ return fields;
+}
+
/*! \brief same as realtime_ldap_base_ap but take variable arguments count list
*/
static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
const char *basedn, const char *table_name, ...)
{
+ RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
struct ast_variable **vars = NULL;
va_list ap;
va_start(ap, table_name);
- vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, ap);
+ fields = realtime_arguments_to_fields(ap);
va_end(ap);
+ vars = realtime_ldap_base_ap(entries_count_ptr, basedn, table_name, fields);
+
return vars;
}
@@ -967,9 +985,9 @@ static struct ast_variable **realtime_ldap_base(unsigned int *entries_count_ptr,
* For Realtime Dynamic(i.e., switch, queues, and directory)
*/
static struct ast_variable *realtime_ldap(const char *basedn,
- const char *table_name, va_list ap)
+ const char *table_name, const struct ast_variable *fields)
{
- struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, ap);
+ struct ast_variable **vars = realtime_ldap_base_ap(NULL, basedn, table_name, fields);
struct ast_variable *var = NULL;
if (vars) {
@@ -1002,22 +1020,19 @@ static struct ast_variable *realtime_ldap(const char *basedn,
* I think this function returns Realtime dynamic objects
*/
static struct ast_config *realtime_multi_ldap(const char *basedn,
- const char *table_name, va_list ap)
+ const char *table_name, const struct ast_variable *fields)
{
char *op;
const char *initfield = NULL;
- const char *newparam, *newval;
struct ast_variable **vars =
- realtime_ldap_base_ap(NULL, basedn, table_name, ap);
+ realtime_ldap_base_ap(NULL, basedn, table_name, fields);
struct ast_config *cfg = NULL;
- newparam = va_arg(ap, const char *);
- newval = va_arg(ap, const char *);
- if (!newparam || !newval) {
+ if (!fields) {
ast_log(LOG_WARNING, "realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
return NULL;
}
- initfield = ast_strdupa(newparam);
+ initfield = ast_strdupa(fields->name);
if ((op = strchr(initfield, ' '))) {
*op = '\0';
}
@@ -1207,13 +1222,13 @@ static struct ast_config *config_ldap(const char *basedn, const char *table_name
/* \brief Function to update a set of values in ldap static mode
*/
static int update_ldap(const char *basedn, const char *table_name, const char *attribute,
- const char *lookup, va_list ap)
+ const char *lookup, const struct ast_variable *fields)
{
int error = 0;
LDAPMessage *ldap_entry = NULL;
LDAPMod **ldap_mods;
- const char *newparam = NULL;
- const char *newval = NULL;
+ const char *newparam;
+ const struct ast_variable *field = fields;
char *dn;
int num_entries = 0;
int i = 0;
@@ -1270,10 +1285,8 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
/* Create the modification array with the parameter/value pairs we were given,
* if there are several parameters with the same name, we collect them into
* one parameter/value pair and delimit them with a semicolon */
- newparam = va_arg(ap, const char *);
- newparam = convert_attribute_name_to_ldap(table_config, newparam);
- newval = va_arg(ap, const char *);
- if (!newparam || !newval) {
+ newparam = convert_attribute_name_to_ldap(table_config, field->name);
+ if (!newparam) {
ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
return -1;
}
@@ -1286,19 +1299,18 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
ldap_mods[0]->mod_type = ldap_strdup(newparam);
ldap_mods[0]->mod_values = ast_calloc(sizeof(char *), 2);
- ldap_mods[0]->mod_values[0] = ldap_strdup(newval);
+ ldap_mods[0]->mod_values[0] = ldap_strdup(field->value);
- while ((newparam = va_arg(ap, const char *))) {
- newparam = convert_attribute_name_to_ldap(table_config, newparam);
- newval = va_arg(ap, const char *);
+ while ((field = field->next)) {
+ newparam = convert_attribute_name_to_ldap(table_config, field->name);
mod_exists = 0;
for (i = 0; i < mods_size - 1; i++) {
if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
/* We have the parameter allready, adding the value as a semicolon delimited value */
- ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
+ ldap_mods[i]->mod_values[0] = ldap_memrealloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2));
strcat(ldap_mods[i]->mod_values[0], ";");
- strcat(ldap_mods[i]->mod_values[0], newval);
+ strcat(ldap_mods[i]->mod_values[0], field->value);
mod_exists = 1;
break;
}
@@ -1315,14 +1327,14 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
ldap_mods[mods_size - 2]->mod_type = ldap_memcalloc(sizeof(char), strlen(newparam) + 1);
strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
- if (strlen(newval) == 0) {
+ if (strlen(field->value) == 0) {
ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_DELETE;
} else {
ldap_mods[mods_size - 2]->mod_op = LDAP_MOD_REPLACE;
ldap_mods[mods_size - 2]->mod_values = ldap_memcalloc(sizeof(char *), 2);
- ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(newval) + 1);
- strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
+ ldap_mods[mods_size - 2]->mod_values[0] = ldap_memcalloc(sizeof(char), strlen(field->value) + 1);
+ strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
}
}
}
@@ -1390,13 +1402,13 @@ static int update_ldap(const char *basedn, const char *table_name, const char *a
return num_entries;
}
-static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
+static int update2_ldap(const char *basedn, const char *table_name, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
{
int error = 0;
LDAPMessage *ldap_entry = NULL;
LDAPMod **ldap_mods;
- const char *newparam = NULL;
- const char *newval = NULL;
+ const char *newparam;
+ const struct ast_variable *field;
char *dn;
int num_entries = 0;
int i = 0;
@@ -1448,19 +1460,17 @@ static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
}
/* Get multiple lookup keyfields and values */
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- append_var_and_value_to_filter(&filter, table_config, newparam, newval);
+ for (field = lookup_fields; field; field = field->next) {
+ append_var_and_value_to_filter(&filter, table_config, field->name, field->value);
}
ast_str_append(&filter, 0, ")");
/* Create the modification array with the parameter/value pairs we were given,
* if there are several parameters with the same name, we collect them into
* one parameter/value pair and delimit them with a semicolon */
- newparam = va_arg(ap, const char *);
- newparam = convert_attribute_name_to_ldap(table_config, newparam);
- newval = va_arg(ap, const char *);
- if (!newparam || !newval) {
+ field = update_fields;
+ newparam = convert_attribute_name_to_ldap(table_config, field->name);
+ if (!newparam) {
ast_log(LOG_WARNING, "LINE(%d): need at least one parameter to modify.\n", __LINE__);
ast_free(filter);
ast_free(clean_basedn);
@@ -1476,20 +1486,19 @@ static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
strcpy(ldap_mods[0]->mod_type, newparam);
ldap_mods[0]->mod_values = ast_calloc(sizeof(char), 2);
- ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
- strcpy(ldap_mods[0]->mod_values[0], newval);
+ ldap_mods[0]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
+ strcpy(ldap_mods[0]->mod_values[0], field->value);
- while ((newparam = va_arg(ap, const char *))) {
- newparam = convert_attribute_name_to_ldap(table_config, newparam);
- newval = va_arg(ap, const char *);
+ while ((field = field->next)) {
+ newparam = convert_attribute_name_to_ldap(table_config, field->name);
mod_exists = 0;
for (i = 0; i < mods_size - 1; i++) {
if (ldap_mods[i]&& !strcmp(ldap_mods[i]->mod_type, newparam)) {
/* We have the parameter allready, adding the value as a semicolon delimited value */
- ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(newval) + 2));
+ ldap_mods[i]->mod_values[0] = ast_realloc(ldap_mods[i]->mod_values[0], sizeof(char) * (strlen(ldap_mods[i]->mod_values[0]) + strlen(field->value) + 2));
strcat(ldap_mods[i]->mod_values[0], ";");
- strcat(ldap_mods[i]->mod_values[0], newval);
+ strcat(ldap_mods[i]->mod_values[0], field->value);
mod_exists = 1;
break;
}
@@ -1508,8 +1517,8 @@ static int update2_ldap(const char *basedn, const char *table_name, va_list ap)
strcpy(ldap_mods[mods_size - 2]->mod_type, newparam);
ldap_mods[mods_size - 2]->mod_values = ast_calloc(sizeof(char *), 2);
- ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(newval) + 1);
- strcpy(ldap_mods[mods_size - 2]->mod_values[0], newval);
+ ldap_mods[mods_size - 2]->mod_values[0] = ast_calloc(sizeof(char), strlen(field->value) + 1);
+ strcpy(ldap_mods[mods_size - 2]->mod_values[0], field->value);
}
}
/* freeing ldap_mods further down */
diff --git a/res/res_config_odbc.c b/res/res_config_odbc.c
index 66e15a02b..524912a9e 100644
--- a/res/res_config_odbc.c
+++ b/res/res_config_odbc.c
@@ -55,7 +55,7 @@ struct custom_prepare_struct {
AST_DECLARE_STRING_FIELDS(
AST_STRING_FIELD(encoding)[256];
);
- va_list ap;
+ const struct ast_variable *fields;
unsigned long long skip;
};
@@ -73,10 +73,9 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
{
int res, x = 1, count = 0;
struct custom_prepare_struct *cps = data;
- const char *newparam, *newval;
+ const struct ast_variable *field;
char encodebuf[1024];
SQLHSTMT stmt;
- va_list ap;
res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
@@ -93,14 +92,14 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
return NULL;
}
- va_copy(ap, cps->ap);
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
+ for (field = cps->fields; field; field = field->next) {
+ const char *newval = field->value;
+
if ((1LL << count++) & cps->skip) {
- ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", newparam, newval, 1LL << (count - 1), cps->skip);
+ ast_debug(1, "Skipping field '%s'='%s' (%llo/%llo)\n", field->name, newval, 1LL << (count - 1), cps->skip);
continue;
}
- ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, newparam, newval);
+ ast_debug(1, "Parameter %d ('%s') = '%s'\n", x, field->name, newval);
if (strchr(newval, ';') || strchr(newval, '^')) {
char *eptr = encodebuf;
const char *vptr = newval;
@@ -123,7 +122,6 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
}
SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
}
- va_end(ap);
if (!ast_strlen_zero(cps->extra))
SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(cps->extra), 0, (void *)cps->extra, 0, NULL);
@@ -143,7 +141,7 @@ static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
* \retval var on success
* \retval NULL on failure
*/
-static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
+static struct ast_variable *realtime_odbc(const char *database, const char *table, const struct ast_variable *fields)
{
struct odbc_obj *obj;
SQLHSTMT stmt;
@@ -151,7 +149,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
char coltitle[256];
char rowdata[2048];
char *op;
- const char *newparam;
+ const struct ast_variable *field = fields;
char *stringp;
char *chunk;
SQLSMALLINT collen;
@@ -164,10 +162,13 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
SQLSMALLINT decimaldigits;
SQLSMALLINT nullable;
SQLLEN indicator;
- va_list aq;
- struct custom_prepare_struct cps = { .sql = sql };
+ struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
+ if (!fields) {
+ return NULL;
+ }
+
if (ast_string_field_init(&cps, 256)) {
return NULL;
}
@@ -185,29 +186,16 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
return NULL;
}
- va_copy(aq, ap);
- newparam = va_arg(aq, const char *);
- if (!newparam) {
- va_end(aq);
- ast_odbc_release_obj(obj);
- ast_string_field_free_memory(&cps);
- return NULL;
- }
- va_arg(aq, const char *);
- op = !strchr(newparam, ' ') ? " =" : "";
- snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
- strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
- while((newparam = va_arg(aq, const char *))) {
- op = !strchr(newparam, ' ') ? " =" : "";
- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
- strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
- va_arg(aq, const char *);
+ op = !strchr(field->name, ' ') ? " =" : "";
+ snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
+ strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
+ while ((field = field->next)) {
+ op = !strchr(field->name, ' ') ? " =" : "";
+ snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
+ strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
}
- va_end(aq);
- va_copy(cps.ap, ap);
stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
- va_end(cps.ap);
if (!stmt) {
ast_odbc_release_obj(obj);
@@ -310,7 +298,7 @@ static struct ast_variable *realtime_odbc(const char *database, const char *tabl
* \retval var on success
* \retval NULL on failure
*/
-static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
+static struct ast_config *realtime_multi_odbc(const char *database, const char *table, const struct ast_variable *fields)
{
struct odbc_obj *obj;
SQLHSTMT stmt;
@@ -319,7 +307,7 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
char rowdata[2048];
const char *initfield;
char *op;
- const char *newparam;
+ const struct ast_variable *field = fields;
char *stringp;
char *chunk;
SQLSMALLINT collen;
@@ -335,51 +323,36 @@ static struct ast_config *realtime_multi_odbc(const char *database, const char *
SQLSMALLINT decimaldigits;
SQLSMALLINT nullable;
SQLLEN indicator;
- struct custom_prepare_struct cps = { .sql = sql };
- va_list aq;
+ struct custom_prepare_struct cps = { .sql = sql, .fields = fields, };
- if (!table || ast_string_field_init(&cps, 256)) {
+ if (!table || !field || ast_string_field_init(&cps, 256)) {
return NULL;
}
-
obj = ast_odbc_request_obj2(database, connected_flag);
if (!obj) {
ast_string_field_free_memory(&cps);
return NULL;
}
- va_copy(aq, ap);
- newparam = va_arg(aq, const char *);
- if (!newparam) {
- va_end(aq);
- ast_odbc_release_obj(obj);
- ast_string_field_free_memory(&cps);
- return NULL;
- }
-
- initfield = ast_strdupa(newparam);
+ initfield = ast_strdupa(field->name);
if ((op = strchr(initfield, ' '))) {
*op = '\0';
}
- va_arg(aq, const char *);
- op = !strchr(newparam, ' ') ? " =" : "";
- snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, newparam, op,
- strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
- while((newparam = va_arg(aq, const char *))) {
- op = !strchr(newparam, ' ') ? " =" : "";
- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", newparam, op,
- strcasestr(newparam, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
- va_arg(aq, const char *);
+ field = field->next;
+ op = !strchr(field->name, ' ') ? " =" : "";
+ snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE %s%s ?%s", table, field->name, op,
+ strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
+ while ((field = field->next)) {
+ op = !strchr(field->name, ' ') ? " =" : "";
+ snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " AND %s%s ?%s", field->name, op,
+ strcasestr(field->name, "LIKE") && !ast_odbc_backslash_is_escape(obj) ? " ESCAPE '\\'" : "");
}
- va_end(aq);
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
- va_copy(cps.ap, ap);
stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
- va_end(cps.ap);
if (!stmt) {
ast_odbc_release_obj(obj);
@@ -478,21 +451,20 @@ next_sql_fetch:;
* \retval number of rows affected
* \retval -1 on failure
*/
-static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
+static int update_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
{
struct odbc_obj *obj;
SQLHSTMT stmt;
char sql[256];
SQLLEN rowcount=0;
- const char *newparam;
+ const struct ast_variable *field = fields;
int res, count = 1;
- va_list aq;
- struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
+ struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
struct odbc_cache_tables *tableptr;
struct odbc_cache_columns *column = NULL;
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
- if (!table) {
+ if (!table || !field) {
return -1;
}
@@ -507,47 +479,32 @@ static int update_odbc(const char *database, const char *table, const char *keyf
return -1;
}
- va_copy(aq, ap);
- newparam = va_arg(aq, const char *);
- if (!newparam) {
- va_end(aq);
- ast_odbc_release_obj(obj);
- ast_odbc_release_table(tableptr);
- ast_string_field_free_memory(&cps);
- return -1;
- }
- va_arg(aq, const char *);
-
- if (tableptr && !ast_odbc_find_column(tableptr, newparam)) {
- ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", newparam, table, database);
+ if (tableptr && !ast_odbc_find_column(tableptr, field->name)) {
+ ast_log(LOG_WARNING, "Key field '%s' does not exist in table '%s@%s'. Update will fail\n", field->name, table, database);
}
- snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
- while((newparam = va_arg(aq, const char *))) {
- va_arg(aq, const char *);
- if ((tableptr && (column = ast_odbc_find_column(tableptr, newparam))) || count > 63) {
+ snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, field->name);
+ while ((field = field->next)) {
+ if ((tableptr && (column = ast_odbc_find_column(tableptr, field->name))) || count > 63) {
/* NULL test for integer-based columns */
- if (ast_strlen_zero(newparam) && tableptr && column && column->nullable && count < 64 &&
+ if (ast_strlen_zero(field->name) && tableptr && column && column->nullable && count < 64 &&
(column->type == SQL_INTEGER || column->type == SQL_BIGINT ||
column->type == SQL_SMALLINT || column->type == SQL_TINYINT ||
column->type == SQL_NUMERIC || column->type == SQL_DECIMAL)) {
- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=NULL", newparam);
+ snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=NULL", field->name);
cps.skip |= (1LL << count);
} else {
- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
+ snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", field->name);
}
} else { /* the column does not exist in the table */
cps.skip |= (1LL << count);
}
count++;
}
- va_end(aq);
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
ast_odbc_release_table(tableptr);
- va_copy(cps.ap, ap);
stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
- va_end(cps.ap);
if (!stmt) {
ast_odbc_release_obj(obj);
@@ -575,17 +532,17 @@ static int update_odbc(const char *database, const char *table, const char *keyf
struct update2_prepare_struct {
const char *database;
const char *table;
- va_list ap;
+ const struct ast_variable *lookup_fields;
+ const struct ast_variable *update_fields;
};
static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
{
int res, x = 1, first = 1;
struct update2_prepare_struct *ups = data;
- const char *newparam, *newval;
+ const struct ast_variable *field;
struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
SQLHSTMT stmt;
- va_list ap;
struct odbc_cache_tables *tableptr = ast_odbc_find_table(ups->database, ups->table);
if (!sql) {
@@ -609,45 +566,30 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
ast_str_set(&sql, 0, "UPDATE %s SET ", ups->table);
- /* Start by finding the second set of parameters */
- va_copy(ap, ups->ap);
-
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- }
-
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- if (ast_odbc_find_column(tableptr, newparam)) {
- ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", newparam);
- SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
+ for (field = ups->update_fields; field; field = field->next) {
+ if (ast_odbc_find_column(tableptr, field->name)) {
+ ast_str_append(&sql, 0, "%s%s=? ", first ? "" : ", ", field->name);
+ SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->name), 0, (void *)field->value, 0, NULL);
first = 0;
} else {
- ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", newparam, ups->table, ups->database);
+ ast_log(LOG_NOTICE, "Not updating column '%s' in '%s@%s' because that column does not exist!\n", field->name, ups->table, ups->database);
}
}
- va_end(ap);
ast_str_append(&sql, 0, "WHERE");
first = 1;
- /* Restart search, because we need to add the search parameters */
- va_copy(ap, ups->ap);
-
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- if (!ast_odbc_find_column(tableptr, newparam)) {
- va_end(ap);
- ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", newparam, ups->table, ups->database);
+ for (field = ups->lookup_fields; field; field = field->next) {
+ if (!ast_odbc_find_column(tableptr, field->name)) {
+ ast_log(LOG_ERROR, "One or more of the criteria columns '%s' on '%s@%s' for this update does not exist!\n", field->name, ups->table, ups->database);
ast_odbc_release_table(tableptr);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
return NULL;
}
- ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", newparam);
- SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(newval), 0, (void *)newval, 0, NULL);
+ ast_str_append(&sql, 0, "%s %s=?", first ? "" : " AND", field->name);
+ SQLBindParameter(stmt, x++, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(field->value), 0, (void *)field->value, 0, NULL);
first = 0;
}
- va_end(ap);
/* Done with the table metadata */
ast_odbc_release_table(tableptr);
@@ -676,11 +618,11 @@ static SQLHSTMT update2_prepare(struct odbc_obj *obj, void *data)
* \retval number of rows affected
* \retval -1 on failure
*/
-static int update2_odbc(const char *database, const char *table, va_list ap)
+static int update2_odbc(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
{
struct odbc_obj *obj;
SQLHSTMT stmt;
- struct update2_prepare_struct ups = { .database = database, .table = table, };
+ struct update2_prepare_struct ups = { .database = database, .table = table, .lookup_fields = lookup_fields, .update_fields = update_fields, };
struct ast_str *sql;
int res;
SQLLEN rowcount = 0;
@@ -689,13 +631,10 @@ static int update2_odbc(const char *database, const char *table, va_list ap)
return -1;
}
- va_copy(ups.ap, ap);
if (!(stmt = ast_odbc_prepare_and_execute(obj, update2_prepare, &ups))) {
- va_end(ups.ap);
ast_odbc_release_obj(obj);
return -1;
}
- va_end(ups.ap);
res = SQLRowCount(stmt, &rowcount);
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
@@ -728,7 +667,7 @@ static int update2_odbc(const char *database, const char *table, va_list ap)
* \retval number of rows affected
* \retval -1 on failure
*/
-static int store_odbc(const char *database, const char *table, va_list ap)
+static int store_odbc(const char *database, const char *table, const struct ast_variable *fields)
{
struct odbc_obj *obj;
SQLHSTMT stmt;
@@ -736,13 +675,12 @@ static int store_odbc(const char *database, const char *table, va_list ap)
char keys[256];
char vals[256];
SQLLEN rowcount=0;
- const char *newparam;
+ const struct ast_variable *field = fields;
int res;
- va_list aq;
- struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
+ struct custom_prepare_struct cps = { .sql = sql, .extra = NULL, .fields = fields, };
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
- if (!table) {
+ if (!table || !field) {
return -1;
}
@@ -751,29 +689,15 @@ static int store_odbc(const char *database, const char *table, va_list ap)
return -1;
}
- va_copy(aq, ap);
-
- newparam = va_arg(aq, const char *);
- if (!newparam) {
- va_end(aq);
- ast_odbc_release_obj(obj);
- return -1;
- }
- va_arg(aq, const char *);
- snprintf(keys, sizeof(keys), "%s", newparam);
+ snprintf(keys, sizeof(keys), "%s", field->name);
ast_copy_string(vals, "?", sizeof(vals));
- while ((newparam = va_arg(aq, const char *))) {
- snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
+ while ((field = field->next)) {
+ snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", field->name);
snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
- va_arg(aq, const char *);
}
- va_end(aq);
snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
-
- va_copy(cps.ap, ap);
stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
- va_end(cps.ap);
if (!stmt) {
ast_odbc_release_obj(obj);
@@ -810,16 +734,15 @@ static int store_odbc(const char *database, const char *table, va_list ap)
* \retval number of rows affected
* \retval -1 on failure
*/
-static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
+static int destroy_odbc(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
{
struct odbc_obj *obj;
SQLHSTMT stmt;
char sql[256];
SQLLEN rowcount=0;
- const char *newparam;
+ const struct ast_variable *field;
int res;
- va_list aq;
- struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
+ struct custom_prepare_struct cps = { .sql = sql, .extra = lookup, .fields = fields, };
struct ast_flags connected_flag = { RES_ODBC_CONNECTED };
if (!table) {
@@ -833,17 +756,12 @@ static int destroy_odbc(const char *database, const char *table, const char *key
snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
- va_copy(aq, ap);
- while((newparam = va_arg(aq, const char *))) {
- snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
- va_arg(aq, const char *);
+ for (field = fields; field; field = field->next) {
+ snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", field->name);
}
- va_end(aq);
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
- va_copy(cps.ap, ap);
stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
- va_end(cps.ap);
if (!stmt) {
ast_odbc_release_obj(obj);
diff --git a/res/res_config_pgsql.c b/res/res_config_pgsql.c
index e3b605812..5af753651 100644
--- a/res/res_config_pgsql.c
+++ b/res/res_config_pgsql.c
@@ -418,7 +418,7 @@ static struct columns *find_column(struct tables *t, const char *colname)
return NULL;
}
-static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, va_list ap)
+static struct ast_variable *realtime_pgsql(const char *database, const char *tablename, const struct ast_variable *fields)
{
PGresult *result = NULL;
int num_rows = 0, pgresult;
@@ -427,7 +427,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
char *stringp;
char *chunk;
char *op;
- const char *newparam, *newval;
+ const struct ast_variable *field = fields;
struct ast_variable *var = NULL, *prev = NULL;
/*
@@ -442,9 +442,7 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
}
/* 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) {
+ if (!field) {
ast_log(LOG_WARNING,
"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
if (pgsqlConn) {
@@ -456,29 +454,28 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
/* 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, ' ') ? "" : " =";
+ op = strchr(field->name, ' ') ? "" : " =";
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
return NULL;
}
- ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, newparam, op, ast_str_buffer(escapebuf));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- if (!strchr(newparam, ' '))
+ ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", tablename, field->name, op, ast_str_buffer(escapebuf));
+ while ((field = field->next)) {
+ if (!strchr(field->name, ' '))
op = " =";
else
op = "";
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
return NULL;
}
- ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
+ ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
}
/* We now have our complete statement; Lets connect to the server and execute it. */
@@ -536,17 +533,17 @@ static struct ast_variable *realtime_pgsql(const char *database, const char *tab
return var;
}
-static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, va_list ap)
+static struct ast_config *realtime_multi_pgsql(const char *database, const char *table, const struct ast_variable *fields)
{
PGresult *result = NULL;
int num_rows = 0, pgresult;
struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
+ const struct ast_variable *field = fields;
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;
@@ -566,9 +563,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
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) {
+ if (!field) {
ast_log(LOG_WARNING,
"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
if (pgsqlConn) {
@@ -579,7 +574,7 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
return NULL;
}
- initfield = ast_strdupa(newparam);
+ initfield = ast_strdupa(field->name);
if ((op = strchr(initfield, ' '))) {
*op = '\0';
}
@@ -587,34 +582,33 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
/* 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, ' '))
+ if (!strchr(field->name, ' '))
op = " =";
else
op = "";
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
ast_config_destroy(cfg);
return NULL;
}
- ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(escapebuf));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- if (!strchr(newparam, ' '))
+ ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(escapebuf));
+ while ((field = field->next)) {
+ if (!strchr(field->name, ' '))
op = " =";
else
op = "";
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
ast_config_destroy(cfg);
return NULL;
}
- ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(escapebuf));
+ ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(escapebuf));
}
if (initfield) {
@@ -696,11 +690,11 @@ static struct ast_config *realtime_multi_pgsql(const char *database, const char
}
static int update_pgsql(const char *database, const char *tablename, const char *keyfield,
- const char *lookup, va_list ap)
+ const char *lookup, const struct ast_variable *fields)
{
PGresult *result = NULL;
int numrows = 0, pgresult;
- const char *newparam, *newval;
+ const struct ast_variable *field = fields;
struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 100);
struct tables *table;
@@ -723,9 +717,7 @@ static int update_pgsql(const char *database, const char *tablename, const char
}
/* 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) {
+ if (!field) {
ast_log(LOG_WARNING,
"PostgreSQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
if (pgsqlConn) {
@@ -738,13 +730,13 @@ static int update_pgsql(const char *database, const char *tablename, const char
/* Check that the column exists in the table */
AST_LIST_TRAVERSE(&table->columns, column, list) {
- if (strcmp(column->name, newparam) == 0) {
+ if (strcmp(column->name, field->name) == 0) {
break;
}
}
if (!column) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: Updating on column '%s', but that column does not exist within the table '%s'!\n", field->name, tablename);
release_table(table);
return -1;
}
@@ -752,30 +744,28 @@ static int update_pgsql(const char *database, const char *tablename, const char
/* 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 */
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
release_table(table);
return -1;
}
- ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, newparam, ast_str_buffer(escapebuf));
+ ast_str_set(&sql, 0, "UPDATE %s SET %s = '%s'", tablename, field->name, ast_str_buffer(escapebuf));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
-
- if (!find_column(table, newparam)) {
- ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
+ while ((field = field->next)) {
+ if (!find_column(table, field->name)) {
+ ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s', but column does not exist!\n", field->name, tablename);
continue;
}
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
release_table(table);
return -1;
}
- ast_str_append(&sql, 0, ", %s = '%s'", newparam, ast_str_buffer(escapebuf));
+ ast_str_append(&sql, 0, ", %s = '%s'", field->name, ast_str_buffer(escapebuf));
}
release_table(table);
@@ -828,12 +818,12 @@ static int update_pgsql(const char *database, const char *tablename, const char
return -1;
}
-static int update2_pgsql(const char *database, const char *tablename, va_list ap)
+static int update2_pgsql(const char *database, const char *tablename, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
{
PGresult *result = NULL;
int numrows = 0, pgresult, first = 1;
struct ast_str *escapebuf = ast_str_thread_get(&escapebuf_buf, 16);
- const char *newparam, *newval;
+ const struct ast_variable *field;
struct ast_str *sql = ast_str_thread_get(&sql_buf, 100);
struct ast_str *where = ast_str_thread_get(&where_buf, 100);
struct tables *table;
@@ -862,22 +852,21 @@ static int update2_pgsql(const char *database, const char *tablename, va_list ap
ast_str_set(&sql, 0, "UPDATE %s SET ", tablename);
ast_str_set(&where, 0, "WHERE");
- while ((newparam = va_arg(ap, const char *))) {
- if (!find_column(table, newparam)) {
- ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", newparam, tablename, database);
+ for (field = lookup_fields; field; field = field->next) {
+ if (!find_column(table, field->name)) {
+ ast_log(LOG_ERROR, "Attempted to update based on criteria column '%s' (%s@%s), but that column does not exist!\n", field->name, tablename, database);
release_table(table);
return -1;
}
- newval = va_arg(ap, const char *);
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
release_table(table);
ast_free(sql);
return -1;
}
- ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", newparam, ast_str_buffer(escapebuf));
+ ast_str_append(&where, 0, "%s %s='%s'", first ? "" : " AND", field->name, ast_str_buffer(escapebuf));
first = 0;
}
@@ -894,24 +883,22 @@ static int update2_pgsql(const char *database, const char *tablename, va_list ap
/* Now retrieve the columns to update */
first = 1;
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
-
+ for (field = update_fields; field; field = field->next) {
/* If the column is not within the table, then skip it */
- if (!find_column(table, newparam)) {
- ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", newparam, tablename, database);
+ if (!find_column(table, field->name)) {
+ ast_log(LOG_NOTICE, "Attempted to update column '%s' in table '%s@%s', but column does not exist!\n", field->name, tablename, database);
continue;
}
- ESCAPE_STRING(escapebuf, newval);
+ ESCAPE_STRING(escapebuf, field->value);
if (pgresult) {
- ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", newval);
+ ast_log(LOG_ERROR, "PostgreSQL RealTime: detected invalid input: '%s'\n", field->value);
release_table(table);
ast_free(sql);
return -1;
}
- ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", newparam, ast_str_buffer(escapebuf));
+ ast_str_append(&sql, 0, "%s %s='%s'", first ? "" : ",", field->name, ast_str_buffer(escapebuf));
}
release_table(table);
@@ -943,7 +930,7 @@ static int update2_pgsql(const char *database, const char *tablename, va_list ap
return -1;
}
-static int store_pgsql(const char *database, const char *table, va_list ap)
+static int store_pgsql(const char *database, const char *table, const struct ast_variable *fields)
{
PGresult *result = NULL;
Oid insertid;
@@ -951,7 +938,7 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
struct ast_str *sql1 = ast_str_thread_get(&sql_buf, 256);
struct ast_str *sql2 = ast_str_thread_get(&where_buf, 256);
int pgresult;
- const char *newparam, *newval;
+ const struct ast_variable *field = fields;
/*
* Ignore database from the extconfig.conf since it was
@@ -965,9 +952,7 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
}
/* 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) {
+ if (!field) {
ast_log(LOG_WARNING,
"PostgreSQL RealTime: Realtime storage requires at least 1 parameter and 1 value to store.\n");
if (pgsqlConn) {
@@ -986,15 +971,14 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
/* 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 */
- ESCAPE_STRING(buf, newparam);
+ ESCAPE_STRING(buf, field->name);
ast_str_set(&sql1, 0, "INSERT INTO %s (%s", table, ast_str_buffer(buf));
- ESCAPE_STRING(buf, newval);
+ ESCAPE_STRING(buf, field->value);
ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- ESCAPE_STRING(buf, newparam);
+ while ((field = field->next)) {
+ ESCAPE_STRING(buf, field->name);
ast_str_append(&sql1, 0, ", %s", ast_str_buffer(buf));
- ESCAPE_STRING(buf, newval);
+ ESCAPE_STRING(buf, field->value);
ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
}
ast_str_append(&sql1, 0, "%s)", ast_str_buffer(sql2));
@@ -1024,14 +1008,14 @@ static int store_pgsql(const char *database, const char *table, va_list ap)
return -1;
}
-static int destroy_pgsql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
+static int destroy_pgsql(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *fields)
{
PGresult *result = NULL;
int numrows = 0;
int pgresult;
struct ast_str *sql = ast_str_thread_get(&sql_buf, 256);
struct ast_str *buf1 = ast_str_thread_get(&where_buf, 60), *buf2 = ast_str_thread_get(&escapebuf_buf, 60);
- const char *newparam, *newval;
+ const struct ast_variable *field;
/*
* Ignore database from the extconfig.conf since it was
@@ -1072,10 +1056,9 @@ static int destroy_pgsql(const char *database, const char *table, const char *ke
ESCAPE_STRING(buf1, keyfield);
ESCAPE_STRING(buf2, lookup);
ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s = '%s'", table, ast_str_buffer(buf1), ast_str_buffer(buf2));
- while ((newparam = va_arg(ap, const char *))) {
- newval = va_arg(ap, const char *);
- ESCAPE_STRING(buf1, newparam);
- ESCAPE_STRING(buf2, newval);
+ for (field = fields; field; field = field->next) {
+ ESCAPE_STRING(buf1, field->name);
+ ESCAPE_STRING(buf2, field->value);
ast_str_append(&sql, 0, " AND %s = '%s'", ast_str_buffer(buf1), ast_str_buffer(buf2));
}
diff --git a/res/res_config_sqlite3.c b/res/res_config_sqlite3.c
index 4b2d36598..0a4b1acac 100644
--- a/res/res_config_sqlite3.c
+++ b/res/res_config_sqlite3.c
@@ -61,12 +61,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
***/
static struct ast_config *realtime_sqlite3_load(const char *database, const char *table, const char *configfile, struct ast_config *config, struct ast_flags flags, const char *suggested_include_file, const char *who_asked);
-static struct ast_variable *realtime_sqlite3(const char *database, const char *table, va_list ap);
-static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, va_list ap);
-static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
-static int realtime_sqlite3_update2(const char *database, const char *table, va_list ap);
-static int realtime_sqlite3_store(const char *database, const char *table, va_list ap);
-static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
+static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields);
+static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields);
+static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
+static int realtime_sqlite3_update2(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields);
+static int realtime_sqlite3_store(const char *database, const char *table, const struct ast_variable *fields);
+static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
static int realtime_sqlite3_require(const char *database, const char *table, va_list ap);
static int realtime_sqlite3_unload(const char *database, const char *table);
@@ -648,10 +648,10 @@ static struct ast_config *realtime_sqlite3_load(const char *database, const char
}
/*! \brief Helper function for single and multi-row realtime load functions */
-static int realtime_sqlite3_helper(const char *database, const char *table, va_list ap, int is_multi, void *arg)
+static int realtime_sqlite3_helper(const char *database, const char *table, const struct ast_variable *fields, int is_multi, void *arg)
{
struct ast_str *sql;
- const char *param, *value;
+ const struct ast_variable *field;
int first = 1;
if (ast_strlen_zero(table)) {
@@ -663,14 +663,14 @@ static int realtime_sqlite3_helper(const char *database, const char *table, va_l
return -1;
}
- while ((param = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
+ for (field = fields; field; field = field->next) {
if (first) {
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s %s", sqlite3_escape_table(table),
- sqlite3_escape_column_op(param), sqlite3_escape_value(value));
+ sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
first = 0;
} else {
- ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(param),
- sqlite3_escape_value(value));
+ ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name),
+ sqlite3_escape_value(field->value));
}
}
@@ -691,11 +691,11 @@ static int realtime_sqlite3_helper(const char *database, const char *table, va_l
/*! \brief Realtime callback for a single row query
* \return ast_variable list for single result on success, NULL on empty/failure
*/
-static struct ast_variable *realtime_sqlite3(const char *database, const char *table, va_list ap)
+static struct ast_variable *realtime_sqlite3(const char *database, const char *table, const struct ast_variable *fields)
{
struct ast_variable *result_row = NULL;
- realtime_sqlite3_helper(database, table, ap, 0, &result_row);
+ realtime_sqlite3_helper(database, table, fields, 0, &result_row);
return result_row;
}
@@ -703,7 +703,7 @@ static struct ast_variable *realtime_sqlite3(const char *database, const char *t
/*! \brief Realtime callback for a multi-row query
* \return ast_config containing possibly many results on success, NULL on empty/failure
*/
-static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, va_list ap)
+static struct ast_config *realtime_sqlite3_multi(const char *database, const char *table, const struct ast_variable *fields)
{
struct ast_config *cfg;
@@ -711,7 +711,7 @@ static struct ast_config *realtime_sqlite3_multi(const char *database, const cha
return NULL;
}
- if (realtime_sqlite3_helper(database, table, ap, 1, cfg)) {
+ if (realtime_sqlite3_helper(database, table, fields, 1, cfg)) {
ast_config_destroy(cfg);
return NULL;
}
@@ -722,10 +722,10 @@ static struct ast_config *realtime_sqlite3_multi(const char *database, const cha
/*! \brief Realtime callback for updating a row based on a single criteria
* \return Number of rows affected or -1 on error
*/
-static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap)
+static int realtime_sqlite3_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
{
struct ast_str *sql;
- const char *key, *value;
+ const struct ast_variable *field;
int first = 1, res;
if (ast_strlen_zero(table)) {
@@ -737,13 +737,13 @@ static int realtime_sqlite3_update(const char *database, const char *table, cons
return -1;
}
- while ((key = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
+ for (field = fields; field; field = field->next) {
if (first) {
ast_str_set(&sql, 0, "UPDATE %s SET %s = %s",
- sqlite3_escape_table(table), sqlite3_escape_column(key), sqlite3_escape_value(value));
+ sqlite3_escape_table(table), sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
first = 0;
} else {
- ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(key), sqlite3_escape_value(value));
+ ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
}
}
@@ -758,11 +758,11 @@ static int realtime_sqlite3_update(const char *database, const char *table, cons
/*! \brief Realtime callback for updating a row based on multiple criteria
* \return Number of rows affected or -1 on error
*/
-static int realtime_sqlite3_update2(const char *database, const char *table, va_list ap)
+static int realtime_sqlite3_update2(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
{
struct ast_str *sql;
struct ast_str *where_clause;
- const char *key, *value;
+ const struct ast_variable *field;
int first = 1, res;
if (ast_strlen_zero(table)) {
@@ -779,22 +779,22 @@ static int realtime_sqlite3_update2(const char *database, const char *table, va_
return -1;
}
- while ((key = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
+ for (field = lookup_fields; field; field = field->next) {
if (first) {
- ast_str_set(&where_clause, 0, " WHERE %s %s", sqlite3_escape_column_op(key), sqlite3_escape_value(value));
+ ast_str_set(&where_clause, 0, " WHERE %s %s", sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
first = 0;
} else {
- ast_str_append(&where_clause, 0, " AND %s %s", sqlite3_escape_column_op(key), sqlite3_escape_value(value));
+ ast_str_append(&where_clause, 0, " AND %s %s", sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
}
}
first = 1;
- while ((key = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
+ for (field = update_fields; field; field = field->next) {
if (first) {
- ast_str_set(&sql, 0, "UPDATE %s SET %s = %s", sqlite3_escape_table(table), sqlite3_escape_column(key), sqlite3_escape_value(value));
+ ast_str_set(&sql, 0, "UPDATE %s SET %s = %s", sqlite3_escape_table(table), sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
first = 0;
} else {
- ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(key), sqlite3_escape_value(value));
+ ast_str_append(&sql, 0, ", %s = %s", sqlite3_escape_column(field->name), sqlite3_escape_value(field->value));
}
}
@@ -811,10 +811,10 @@ static int realtime_sqlite3_update2(const char *database, const char *table, va_
/*! \brief Realtime callback for inserting a row
* \return Number of rows affected or -1 on error
*/
-static int realtime_sqlite3_store(const char *database, const char *table, va_list ap)
+static int realtime_sqlite3_store(const char *database, const char *table, const struct ast_variable *fields)
{
struct ast_str *sql, *values;
- const char *column, *value;
+ const struct ast_variable *field;
int first = 1, res;
if (ast_strlen_zero(table)) {
@@ -831,14 +831,14 @@ static int realtime_sqlite3_store(const char *database, const char *table, va_li
return -1;
}
- while ((column = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
+ for (field = fields; field; field = field->next) {
if (first) {
- ast_str_set(&sql, 0, "INSERT INTO %s (%s", sqlite3_escape_table(table), sqlite3_escape_column(column));
- ast_str_set(&values, 0, ") VALUES (%s", sqlite3_escape_value(value));
+ ast_str_set(&sql, 0, "INSERT INTO %s (%s", sqlite3_escape_table(table), sqlite3_escape_column(field->name));
+ ast_str_set(&values, 0, ") VALUES (%s", sqlite3_escape_value(field->value));
first = 0;
} else {
- ast_str_append(&sql, 0, ", %s", sqlite3_escape_column(column));
- ast_str_append(&values, 0, ", %s", sqlite3_escape_value(value));
+ ast_str_append(&sql, 0, ", %s", sqlite3_escape_column(field->name));
+ ast_str_append(&values, 0, ", %s", sqlite3_escape_value(field->value));
}
}
@@ -855,10 +855,10 @@ static int realtime_sqlite3_store(const char *database, const char *table, va_li
/*! \brief Realtime callback for deleting a row
* \return Number of rows affected or -1 on error
*/
-static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap)
+static int realtime_sqlite3_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
{
struct ast_str *sql;
- const char *param, *value;
+ const struct ast_variable *field;
int first = 1, res;
if (ast_strlen_zero(table)) {
@@ -870,13 +870,13 @@ static int realtime_sqlite3_destroy(const char *database, const char *table, con
return -1;
}
- while ((param = va_arg(ap, const char *)) && (value = va_arg(ap, const char *))) {
+ for (field = fields; field; field = field->next) {
if (first) {
ast_str_set(&sql, 0, "DELETE FROM %s WHERE %s %s", sqlite3_escape_table(table),
- sqlite3_escape_column_op(param), sqlite3_escape_value(value));
+ sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
first = 0;
} else {
- ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(param), sqlite3_escape_value(value));
+ ast_str_append(&sql, 0, " AND %s %s", sqlite3_escape_column_op(field->name), sqlite3_escape_value(field->value));
}
}
diff --git a/res/res_sorcery_realtime.c b/res/res_sorcery_realtime.c
new file mode 100644
index 000000000..29517c80d
--- /dev/null
+++ b/res/res_sorcery_realtime.c
@@ -0,0 +1,252 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * Joshua Colp <jcolp@digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ *
+ * \brief Sorcery Realtime Object Wizard
+ *
+ * \author Joshua Colp <jcolp@digium.com>
+ */
+
+/*** MODULEINFO
+ <support_level>core</support_level>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <regex.h>
+
+#include "asterisk/module.h"
+#include "asterisk/sorcery.h"
+
+/*! \brief They key field used to store the unique identifier for the object */
+#define UUID_FIELD "id"
+
+static void *sorcery_realtime_open(const char *data);
+static int sorcery_realtime_create(const struct ast_sorcery *sorcery, void *data, void *object);
+static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id);
+static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields);
+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);
+static void sorcery_realtime_retrieve_regex(const struct ast_sorcery *sorcery, void *data, const char *type, struct ao2_container *objects, const char *regex);
+static int sorcery_realtime_update(const struct ast_sorcery *sorcery, void *data, void *object);
+static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object);
+static void sorcery_realtime_close(void *data);
+
+static struct ast_sorcery_wizard realtime_object_wizard = {
+ .name = "realtime",
+ .open = sorcery_realtime_open,
+ .create = sorcery_realtime_create,
+ .retrieve_id = sorcery_realtime_retrieve_id,
+ .retrieve_fields = sorcery_realtime_retrieve_fields,
+ .retrieve_multiple = sorcery_realtime_retrieve_multiple,
+ .retrieve_regex = sorcery_realtime_retrieve_regex,
+ .update = sorcery_realtime_update,
+ .delete = sorcery_realtime_delete,
+ .close = sorcery_realtime_close,
+};
+
+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) ? -1 : 0;
+}
+
+/*! \brief Internal helper function which returns a filtered objectset, basically removes the id field */
+static struct ast_variable *sorcery_realtime_filter_objectset(struct ast_variable *objectset, struct ast_variable **id)
+{
+ struct ast_variable *previous = NULL, *field;
+
+ for (field = objectset; field; field = field->next) {
+ if (!strcmp(field->name, UUID_FIELD)) {
+ *id = field;
+
+ if (previous) {
+ previous->next = field->next;
+ } else {
+ objectset = field->next;
+ }
+
+ field->next = NULL;
+ break;
+ }
+ previous = field;
+ }
+
+ return objectset;
+}
+
+static void *sorcery_realtime_retrieve_fields(const struct ast_sorcery *sorcery, void *data, const char *type, const struct ast_variable *fields)
+{
+ const char *family = data;
+ RAII_VAR(struct ast_variable *, objectset, NULL, ast_variables_destroy);
+ RAII_VAR(struct ast_variable *, id, NULL, ast_variables_destroy);
+ void *object = NULL;
+
+ if (!(objectset = ast_load_realtime_fields(family, fields))) {
+ return NULL;
+ }
+
+ objectset = sorcery_realtime_filter_objectset(objectset, &id);
+
+ if (!id || !(object = ast_sorcery_alloc(sorcery, type, id->value)) || ast_sorcery_objectset_apply(sorcery, object, objectset)) {
+ return NULL;
+ }
+
+ return object;
+}
+
+static void *sorcery_realtime_retrieve_id(const struct ast_sorcery *sorcery, void *data, const char *type, const char *id)
+{
+ RAII_VAR(struct ast_variable *, fields, ast_variable_new(UUID_FIELD, id, ""), ast_variables_destroy);
+
+ return sorcery_realtime_retrieve_fields(sorcery, data, type, fields);
+}
+
+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);
+ char *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(rows, row))) {
+ struct ast_variable *objectset = ast_category_root(rows, 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);
+
+ if (id && (object = ast_sorcery_alloc(sorcery, type, id->value)) && !ast_sorcery_objectset_apply(sorcery, object, objectset)) {
+ ao2_link(objects, object);
+ }
+
+ /* If the id is the root of the row it will be destroyed during ast_config_destroy */
+ if (id == ast_category_root(rows, row)) {
+ id = NULL;
+ }
+ }
+}
+
+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) + 2];
+ 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 */
+ if (regex[0] != '^') {
+ return;
+ }
+
+ snprintf(field, sizeof(field), "%s LIKE", UUID_FIELD);
+ snprintf(value, sizeof(value), "%s%%", regex + 1);
+
+ if (!(fields = ast_variable_new(field, value, ""))) {
+ return;
+ }
+
+ sorcery_realtime_retrieve_multiple(sorcery, data, type, objects, fields);
+}
+
+static int sorcery_realtime_update(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);
+
+ if (!fields) {
+ return -1;
+ }
+
+ return (ast_update_realtime_fields(family, UUID_FIELD, ast_sorcery_object_get_id(object), fields) <= 0) ? -1 : 0;
+}
+
+static int sorcery_realtime_delete(const struct ast_sorcery *sorcery, void *data, void *object)
+{
+ const char *family = data;
+
+ return (ast_destroy_realtime_fields(family, UUID_FIELD, ast_sorcery_object_get_id(object), NULL) <= 0) ? -1 : 0;
+}
+
+static void *sorcery_realtime_open(const char *data)
+{
+ /* We require a prefix for family string generation, or else stuff could mix together */
+ if (ast_strlen_zero(data) || !ast_realtime_is_mapping_defined(data)) {
+ return NULL;
+ }
+
+ return ast_strdup(data);
+}
+
+static void sorcery_realtime_close(void *data)
+{
+ ast_free(data);
+}
+
+static int load_module(void)
+{
+ if (ast_sorcery_wizard_register(&realtime_object_wizard)) {
+ return AST_MODULE_LOAD_DECLINE;
+ }
+
+ return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int unload_module(void)
+{
+ ast_sorcery_wizard_unregister(&realtime_object_wizard);
+ return 0;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Sorcery Realtime Object Wizard",
+ .load = load_module,
+ .unload = unload_module,
+ .load_pri = AST_MODPRI_REALTIME_DRIVER,
+);