mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-19 11:42:27 +00:00
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
This commit is contained in:
6
CHANGES
6
CHANGES
@@ -147,6 +147,12 @@ XMPP
|
||||
If no resources exist or all are unavailable the device state is considered
|
||||
to be unavailable.
|
||||
|
||||
Sorcery
|
||||
------------------
|
||||
* All future modules which utilize Sorcery for object persistence must have a
|
||||
column named "id" within their schema when using the Sorcery realtime module.
|
||||
This column must be able to contain a string of up to 128 characters in length.
|
||||
|
||||
------------------------------------------------------------------------------
|
||||
--- Functionality changes from Asterisk 10 to Asterisk 11 --------------------
|
||||
------------------------------------------------------------------------------
|
||||
|
@@ -316,7 +316,7 @@ static char *decode_chunk(char *chunk)
|
||||
return orig;
|
||||
}
|
||||
|
||||
static struct ast_variable *realtime_mysql(const char *database, const char *table, va_list ap)
|
||||
static struct ast_variable *realtime_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
|
||||
{
|
||||
struct mysql_conn *dbh;
|
||||
MYSQL_RES *result;
|
||||
@@ -328,7 +328,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
|
||||
char *stringp;
|
||||
char *chunk;
|
||||
char *op;
|
||||
const char *newparam, *newval;
|
||||
const struct ast_variable *field = rt_fields;
|
||||
struct ast_variable *var=NULL, *prev=NULL;
|
||||
|
||||
if (!(dbh = find_database(database, 0))) {
|
||||
@@ -343,7 +343,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
|
||||
}
|
||||
|
||||
/* Get the first parameter and first value in our list of passed paramater/value pairs */
|
||||
if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *))) {
|
||||
if (!field) {
|
||||
ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
|
||||
release_database(dbh);
|
||||
return NULL;
|
||||
@@ -358,21 +358,20 @@ static struct ast_variable *realtime_mysql(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 */
|
||||
|
||||
if (!strchr(newparam, ' '))
|
||||
if (!strchr(field->name, ' '))
|
||||
op = " =";
|
||||
else
|
||||
op = "";
|
||||
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(buf));
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
newval = va_arg(ap, const char *);
|
||||
if (!strchr(newparam, ' '))
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
|
||||
while ((field = field->next)) {
|
||||
if (!strchr(field->name, ' '))
|
||||
op = " =";
|
||||
else
|
||||
op = "";
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(buf));
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
|
||||
}
|
||||
|
||||
ast_debug(1, "MySQL RealTime: Retrieve SQL: %s\n", ast_str_buffer(sql));
|
||||
@@ -417,7 +416,7 @@ static struct ast_variable *realtime_mysql(const char *database, const char *tab
|
||||
return var;
|
||||
}
|
||||
|
||||
static struct ast_config *realtime_multi_mysql(const char *database, const char *table, va_list ap)
|
||||
static struct ast_config *realtime_multi_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
|
||||
{
|
||||
struct mysql_conn *dbh;
|
||||
MYSQL_RES *result;
|
||||
@@ -430,7 +429,7 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
|
||||
char *stringp;
|
||||
char *chunk;
|
||||
char *op;
|
||||
const char *newparam, *newval;
|
||||
const struct ast_variable *field = rt_fields;
|
||||
struct ast_variable *var = NULL;
|
||||
struct ast_config *cfg = NULL;
|
||||
struct ast_category *cat = NULL;
|
||||
@@ -454,14 +453,14 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
|
||||
}
|
||||
|
||||
/* Get the first parameter and first value in our list of passed paramater/value pairs */
|
||||
if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *))) {
|
||||
if (!field) {
|
||||
ast_log(LOG_WARNING, "MySQL RealTime: Realtime retrieval requires at least 1 parameter and 1 value to search on.\n");
|
||||
ast_config_destroy(cfg);
|
||||
release_database(dbh);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
initfield = ast_strdupa(newparam);
|
||||
initfield = ast_strdupa(field->name);
|
||||
if ((op = strchr(initfield, ' '))) {
|
||||
*op = '\0';
|
||||
}
|
||||
@@ -476,18 +475,17 @@ static struct ast_config *realtime_multi_mysql(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(buf, newval);
|
||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, newparam, op, ast_str_buffer(buf));
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
newval = va_arg(ap, const char *);
|
||||
if (!strchr(newparam, ' ')) op = " ="; else op = "";
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, " AND %s%s '%s'", newparam, op, ast_str_buffer(buf));
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_set(&sql, 0, "SELECT * FROM %s WHERE %s%s '%s'", table, field->name, op, ast_str_buffer(buf));
|
||||
while ((field = field->next)) {
|
||||
if (!strchr(field->name, ' ')) op = " ="; else op = "";
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_append(&sql, 0, " AND %s%s '%s'", field->name, op, ast_str_buffer(buf));
|
||||
}
|
||||
|
||||
if (initfield) {
|
||||
@@ -540,11 +538,11 @@ static struct ast_config *realtime_multi_mysql(const char *database, const char
|
||||
return cfg;
|
||||
}
|
||||
|
||||
static int update_mysql(const char *database, const char *tablename, const char *keyfield, const char *lookup, va_list ap)
|
||||
static int update_mysql(const char *database, const char *tablename, const char *keyfield, const char *lookup, const struct ast_variable *rt_fields)
|
||||
{
|
||||
struct mysql_conn *dbh;
|
||||
my_ulonglong numrows;
|
||||
const char *newparam, *newval;
|
||||
const struct ast_variable *field = rt_fields;
|
||||
struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&scratch_buf, 100);
|
||||
struct tables *table;
|
||||
struct columns *column = NULL;
|
||||
@@ -574,7 +572,7 @@ static int update_mysql(const char *database, const char *tablename, const char
|
||||
}
|
||||
|
||||
/* Get the first parameter and first value in our list of passed paramater/value pairs */
|
||||
if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *))) {
|
||||
if (!field) {
|
||||
ast_log(LOG_WARNING, "MySQL RealTime: Realtime update requires at least 1 parameter and 1 value to update.\n");
|
||||
release_table(table);
|
||||
release_database(dbh);
|
||||
@@ -582,8 +580,8 @@ static int update_mysql(const char *database, const char *tablename, const char
|
||||
}
|
||||
|
||||
/* Check that the column exists in the table */
|
||||
if (!(column = find_column(table, newparam))) {
|
||||
ast_log(LOG_ERROR, "MySQL RealTime: Updating column '%s', but that column does not exist within the table '%s' (first pair MUST exist)!\n", newparam, tablename);
|
||||
if (!(column = find_column(table, field->name))) {
|
||||
ast_log(LOG_ERROR, "MySQL RealTime: Updating column '%s', but that column does not exist within the table '%s' (first pair MUST exist)!\n", field->name, tablename);
|
||||
release_table(table);
|
||||
release_database(dbh);
|
||||
return -1;
|
||||
@@ -599,29 +597,27 @@ static int update_mysql(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(buf, newval);
|
||||
ast_str_set(&sql, 0, "UPDATE %s SET `%s` = '%s'", tablename, newparam, ast_str_buffer(buf));
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_set(&sql, 0, "UPDATE %s SET `%s` = '%s'", tablename, field->name, ast_str_buffer(buf));
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
|
||||
internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
}
|
||||
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
newval = va_arg(ap, const char *);
|
||||
|
||||
while ((field = field->next)) {
|
||||
/* If the column is not within the table, then skip it */
|
||||
if (!(column = find_column(table, newparam))) {
|
||||
ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
|
||||
if (!(column = find_column(table, field->name))) {
|
||||
ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", field->name, tablename);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, ", `%s` = '%s'", newparam, ast_str_buffer(buf));
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_append(&sql, 0, ", `%s` = '%s'", field->value, ast_str_buffer(buf));
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
|
||||
internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -653,12 +649,12 @@ static int update_mysql(const char *database, const char *tablename, const char
|
||||
return (int)numrows;
|
||||
}
|
||||
|
||||
static int update2_mysql(const char *database, const char *tablename, va_list ap)
|
||||
static int update2_mysql(const char *database, const char *tablename, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
|
||||
{
|
||||
struct mysql_conn *dbh;
|
||||
my_ulonglong numrows;
|
||||
int first;
|
||||
const char *newparam, *newval;
|
||||
const struct ast_variable *field;
|
||||
struct ast_str *sql = ast_str_thread_get(&sql_buf, 100), *buf = ast_str_thread_get(&scratch_buf, 100);
|
||||
struct ast_str *where = ast_str_thread_get(&sql2_buf, 100);
|
||||
struct tables *table;
|
||||
@@ -697,51 +693,38 @@ static int update2_mysql(const char *database, const char *tablename, va_list ap
|
||||
}
|
||||
|
||||
first = 1;
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
if (!(column = find_column(table, newparam))) {
|
||||
ast_log(LOG_ERROR, "Updating on column '%s', but that column does not exist within the table '%s'!\n", newparam, tablename);
|
||||
for (field = lookup_fields; field; field = field->next) {
|
||||
if (!(column = find_column(table, field->name))) {
|
||||
ast_log(LOG_ERROR, "Updating on column '%s', but that column does not exist within the table '%s'!\n", field->name, tablename);
|
||||
release_table(table);
|
||||
release_database(dbh);
|
||||
return -1;
|
||||
}
|
||||
if (!(newval = va_arg(ap, const char *))) {
|
||||
ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
|
||||
release_table(table);
|
||||
release_database(dbh);
|
||||
return -1;
|
||||
}
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&where, 0, "%s `%s` = '%s'", first ? "" : " AND", newparam, ast_str_buffer(buf));
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_append(&where, 0, "%s `%s` = '%s'", first ? "" : " AND", field->name, ast_str_buffer(buf));
|
||||
first = 0;
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
|
||||
internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
}
|
||||
}
|
||||
|
||||
first = 1;
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
if (!(newval = va_arg(ap, const char *))) {
|
||||
ast_log(LOG_ERROR, "Invalid arguments: no value specified for column '%s' on '%s@%s'\n", newparam, tablename, database);
|
||||
release_table(table);
|
||||
release_database(dbh);
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (field = update_fields; field; field = field->next) {
|
||||
/* If the column is not within the table, then skip it */
|
||||
if (!(column = find_column(table, newparam))) {
|
||||
ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", newparam, tablename);
|
||||
if (!(column = find_column(table, field->name))) {
|
||||
ast_log(LOG_WARNING, "Attempted to update column '%s' in table '%s', but column does not exist!\n", field->name, tablename);
|
||||
continue;
|
||||
}
|
||||
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, "%s `%s` = '%s'", first ? "" : ",", newparam, ast_str_buffer(buf));
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_append(&sql, 0, "%s `%s` = '%s'", first ? "" : ",", field->name, ast_str_buffer(buf));
|
||||
first = 0;
|
||||
|
||||
/* If the column length isn't long enough, give a chance to lengthen it. */
|
||||
if (strncmp(column->type, "char", 4) == 0 || strncmp(column->type, "varchar", 7) == 0) {
|
||||
internal_require(database, tablename, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
internal_require(database, tablename, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -773,14 +756,14 @@ static int update2_mysql(const char *database, const char *tablename, va_list ap
|
||||
return (int)numrows;
|
||||
}
|
||||
|
||||
static int store_mysql(const char *database, const char *table, va_list ap)
|
||||
static int store_mysql(const char *database, const char *table, const struct ast_variable *rt_fields)
|
||||
{
|
||||
struct mysql_conn *dbh;
|
||||
my_ulonglong insertid;
|
||||
struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
|
||||
struct ast_str *sql2 = ast_str_thread_get(&sql2_buf, 16);
|
||||
struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
|
||||
const char *newparam, *newval;
|
||||
const struct ast_variable *field = rt_fields;
|
||||
|
||||
if (!(dbh = find_database(database, 1))) {
|
||||
ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
|
||||
@@ -793,7 +776,7 @@ static int store_mysql(const char *database, const char *table, va_list ap)
|
||||
return -1;
|
||||
}
|
||||
/* Get the first parameter and first value in our list of passed paramater/value pairs */
|
||||
if (!(newparam = va_arg(ap, const char *)) || !(newval = va_arg(ap, const char *))) {
|
||||
if (!field) {
|
||||
ast_log(LOG_WARNING, "MySQL RealTime: Realtime storage requires at least 1 parameter and 1 value to search on.\n");
|
||||
release_database(dbh);
|
||||
return -1;
|
||||
@@ -805,20 +788,17 @@ static int store_mysql(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, newval);
|
||||
ast_str_set(&sql, 0, "INSERT INTO %s (`%s`", table, newparam);
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_set(&sql, 0, "INSERT INTO %s (`%s`", table, field->name);
|
||||
ast_str_set(&sql2, 0, ") VALUES ('%s'", ast_str_buffer(buf));
|
||||
|
||||
internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
internal_require(database, table, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL);
|
||||
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
if ((newval = va_arg(ap, const char *))) {
|
||||
ESCAPE_STRING(buf, newval);
|
||||
} else {
|
||||
ast_str_reset(buf);
|
||||
}
|
||||
if (internal_require(database, table, newparam, RQ_CHAR, ast_str_strlen(buf), SENTINEL) == 0) {
|
||||
ast_str_append(&sql, 0, ", `%s`", newparam);
|
||||
while ((field = field->next)) {
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
|
||||
if (internal_require(database, table, field->name, RQ_CHAR, ast_str_strlen(buf), SENTINEL) == 0) {
|
||||
ast_str_append(&sql, 0, ", `%s`", field->name);
|
||||
ast_str_append(&sql2, 0, ", '%s'", ast_str_buffer(buf));
|
||||
}
|
||||
}
|
||||
@@ -846,13 +826,13 @@ static int store_mysql(const char *database, const char *table, va_list ap)
|
||||
return (int)insertid;
|
||||
}
|
||||
|
||||
static int destroy_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, va_list ap)
|
||||
static int destroy_mysql(const char *database, const char *table, const char *keyfield, const char *lookup, const struct ast_variable *rt_fields)
|
||||
{
|
||||
struct mysql_conn *dbh;
|
||||
my_ulonglong numrows;
|
||||
struct ast_str *sql = ast_str_thread_get(&sql_buf, 16);
|
||||
struct ast_str *buf = ast_str_thread_get(&scratch_buf, 16);
|
||||
const char *newparam, *newval;
|
||||
const struct ast_variable *field;
|
||||
|
||||
if (!(dbh = find_database(database, 1))) {
|
||||
ast_log(LOG_WARNING, "MySQL RealTime: Invalid database specified: '%s' (check res_mysql.conf)\n", database);
|
||||
@@ -884,10 +864,9 @@ static int destroy_mysql(const char *database, const char *table, const char *ke
|
||||
If there is only 1 set, then we have our query. Otherwise, loop thru the list and concat */
|
||||
ESCAPE_STRING(buf, lookup);
|
||||
ast_str_set(&sql, 0, "DELETE FROM %s WHERE `%s` = '%s'", table, keyfield, ast_str_buffer(buf));
|
||||
while ((newparam = va_arg(ap, const char *))) {
|
||||
newval = va_arg(ap, const char *);
|
||||
ESCAPE_STRING(buf, newval);
|
||||
ast_str_append(&sql, 0, " AND `%s` = '%s'", newparam, ast_str_buffer(buf));
|
||||
for (field = rt_fields; field; field = field->next) {
|
||||
ESCAPE_STRING(buf, field->value);
|
||||
ast_str_append(&sql, 0, " AND `%s` = '%s'", field->name, ast_str_buffer(buf));
|
||||
}
|
||||
|
||||
ast_debug(1, "MySQL RealTime: Delete SQL: %s\n", ast_str_buffer(sql));
|
||||
|
@@ -98,12 +98,12 @@ struct ast_variable {
|
||||
};
|
||||
|
||||
typedef struct ast_config *config_load_func(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);
|
||||
typedef struct ast_variable *realtime_var_get(const char *database, const char *table, va_list ap);
|
||||
typedef struct ast_config *realtime_multi_get(const char *database, const char *table, va_list ap);
|
||||
typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
|
||||
typedef int realtime_update2(const char *database, const char *table, va_list ap);
|
||||
typedef int realtime_store(const char *database, const char *table, va_list ap);
|
||||
typedef int realtime_destroy(const char *database, const char *table, const char *keyfield, const char *entity, va_list ap);
|
||||
typedef struct ast_variable *realtime_var_get(const char *database, const char *table, const struct ast_variable *fields);
|
||||
typedef struct ast_config *realtime_multi_get(const char *database, const char *table, const struct ast_variable *fields);
|
||||
typedef int realtime_update(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
|
||||
typedef int realtime_update2(const char *database, const char *table, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields);
|
||||
typedef int realtime_store(const char *database, const char *table, const struct ast_variable *fields);
|
||||
typedef int realtime_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields);
|
||||
|
||||
/*!
|
||||
* \brief Function pointer called to ensure database schema is properly configured for realtime use
|
||||
@@ -305,7 +305,9 @@ int ast_category_exist(const struct ast_config *config, const char *category_nam
|
||||
* You should use the constant SENTINEL to terminate arguments, in
|
||||
* order to preserve cross-platform compatibility.
|
||||
*/
|
||||
struct ast_variable *ast_load_realtime_fields(const char *family, const struct ast_variable *fields);
|
||||
struct ast_variable *ast_load_realtime(const char *family, ...) attribute_sentinel;
|
||||
struct ast_variable *ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields);
|
||||
struct ast_variable *ast_load_realtime_all(const char *family, ...) attribute_sentinel;
|
||||
|
||||
/*!
|
||||
@@ -359,6 +361,24 @@ int ast_unload_realtime(const char *family);
|
||||
*/
|
||||
int ast_realtime_require_field(const char *family, ...) attribute_sentinel;
|
||||
|
||||
/*!
|
||||
* \brief Retrieve realtime configuration
|
||||
*
|
||||
* \param family which family/config to lookup
|
||||
* \param fields list of fields
|
||||
*
|
||||
* \details
|
||||
* This will use builtin configuration backends to look up a particular
|
||||
* entity in realtime and return a variable list of its parameters. Unlike
|
||||
* the ast_load_realtime, this function can return more than one entry and
|
||||
* is thus stored inside a traditional ast_config structure rather than
|
||||
* just returning a linked list of variables.
|
||||
*
|
||||
* \return An ast_config with one or more results
|
||||
* \retval NULL Error or no results returned
|
||||
*/
|
||||
struct ast_config *ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields);
|
||||
|
||||
/*!
|
||||
* \brief Retrieve realtime configuration
|
||||
*
|
||||
@@ -379,6 +399,21 @@ int ast_realtime_require_field(const char *family, ...) attribute_sentinel;
|
||||
*/
|
||||
struct ast_config *ast_load_realtime_multientry(const char *family, ...) attribute_sentinel;
|
||||
|
||||
/*!
|
||||
* \brief Update realtime configuration
|
||||
*
|
||||
* \param family which family/config to be updated
|
||||
* \param keyfield which field to use as the key
|
||||
* \param lookup which value to look for in the key field to match the entry.
|
||||
* \param fields fields to update
|
||||
*
|
||||
* \details
|
||||
* This function is used to update a parameter in realtime configuration space.
|
||||
*
|
||||
* \return Number of rows affected, or -1 on error.
|
||||
*/
|
||||
int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields);
|
||||
|
||||
/*!
|
||||
* \brief Update realtime configuration
|
||||
*
|
||||
@@ -396,6 +431,23 @@ struct ast_config *ast_load_realtime_multientry(const char *family, ...) attribu
|
||||
*/
|
||||
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...) attribute_sentinel;
|
||||
|
||||
/*!
|
||||
* \brief Update realtime configuration
|
||||
*
|
||||
* \param family which family/config to be updated
|
||||
* \param lookup_fields fields used to look up entries
|
||||
* \param update_fields fields to update
|
||||
*
|
||||
* \details
|
||||
* This function is used to update a parameter in realtime configuration space.
|
||||
* It includes the ability to lookup a row based upon multiple key criteria.
|
||||
* As a result, this function includes two sentinel values, one to terminate
|
||||
* lookup values and the other to terminate the listing of fields to update.
|
||||
*
|
||||
* \return Number of rows affected, or -1 on error.
|
||||
*/
|
||||
int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields);
|
||||
|
||||
/*!
|
||||
* \brief Update realtime configuration
|
||||
*
|
||||
@@ -414,6 +466,24 @@ int ast_update_realtime(const char *family, const char *keyfield, const char *lo
|
||||
*/
|
||||
int ast_update2_realtime(const char *family, ...) attribute_sentinel;
|
||||
|
||||
/*!
|
||||
* \brief Create realtime configuration
|
||||
*
|
||||
* \param family which family/config to be created
|
||||
* \param fields fields themselves
|
||||
*
|
||||
* \details
|
||||
* This function is used to create a parameter in realtime configuration space.
|
||||
*
|
||||
* \return Number of rows affected, or -1 on error.
|
||||
*
|
||||
* \note
|
||||
* On the MySQL engine only, for reasons of backwards compatibility, the return
|
||||
* value is the insert ID. This value is nonportable and may be changed in a
|
||||
* future version to match the other engines.
|
||||
*/
|
||||
int ast_store_realtime_fields(const char *family, const struct ast_variable *fields);
|
||||
|
||||
/*!
|
||||
* \brief Create realtime configuration
|
||||
*
|
||||
@@ -434,6 +504,22 @@ int ast_update2_realtime(const char *family, ...) attribute_sentinel;
|
||||
*/
|
||||
int ast_store_realtime(const char *family, ...) attribute_sentinel;
|
||||
|
||||
/*!
|
||||
* \brief Destroy realtime configuration
|
||||
*
|
||||
* \param family which family/config to be destroyed
|
||||
* \param keyfield which field to use as the key
|
||||
* \param lookup which value to look for in the key field to match the entry.
|
||||
* \param fields fields themselves
|
||||
*
|
||||
* \details
|
||||
* This function is used to destroy an entry in realtime configuration space.
|
||||
* Additional params are used as keys.
|
||||
*
|
||||
* \return Number of rows affected, or -1 on error.
|
||||
*/
|
||||
int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields);
|
||||
|
||||
/*!
|
||||
* \brief Destroy realtime configuration
|
||||
*
|
||||
@@ -503,6 +589,19 @@ int ast_config_engine_deregister(struct ast_config_engine *del);
|
||||
*/
|
||||
int ast_realtime_is_mapping_defined(const char *family);
|
||||
|
||||
#ifdef TEST_FRAMEWORK
|
||||
/*!
|
||||
* \brief Add an explicit mapping for a family
|
||||
*
|
||||
* \param name Family name
|
||||
* \param driver Driver to use
|
||||
* \param database Database to access
|
||||
* \param table Table to use
|
||||
* \param priority Priority of this mapping
|
||||
*/
|
||||
int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* \brief Exposed initialization method for core process
|
||||
*
|
||||
|
186
main/config.c
186
main/config.c
@@ -2220,7 +2220,11 @@ static void clear_config_maps(void)
|
||||
}
|
||||
}
|
||||
|
||||
static int append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
|
||||
#ifdef TEST_FRAMEWORK
|
||||
int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
|
||||
#else
|
||||
static int ast_realtime_append_mapping(const char *name, const char *driver, const char *database, const char *table, int priority)
|
||||
#endif
|
||||
{
|
||||
struct ast_config_map *map;
|
||||
char *dst;
|
||||
@@ -2323,13 +2327,13 @@ int read_config_maps(void)
|
||||
continue;
|
||||
if (!strcasecmp(v->name, "sipfriends")) {
|
||||
ast_log(LOG_WARNING, "The 'sipfriends' table is obsolete, update your config to use sippeers instead.\n");
|
||||
append_mapping("sippeers", driver, database, table ? table : "sipfriends", pri);
|
||||
ast_realtime_append_mapping("sippeers", driver, database, table ? table : "sipfriends", pri);
|
||||
} else if (!strcasecmp(v->name, "iaxfriends")) {
|
||||
ast_log(LOG_WARNING, "The 'iaxfriends' table is obsolete, update your config to use iaxusers and iaxpeers, though they can point to the same table.\n");
|
||||
append_mapping("iaxusers", driver, database, table ? table : "iaxfriends", pri);
|
||||
append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends", pri);
|
||||
ast_realtime_append_mapping("iaxusers", driver, database, table ? table : "iaxfriends", pri);
|
||||
ast_realtime_append_mapping("iaxpeers", driver, database, table ? table : "iaxfriends", pri);
|
||||
} else
|
||||
append_mapping(v->name, driver, database, table, pri);
|
||||
ast_realtime_append_mapping(v->name, driver, database, table, pri);
|
||||
}
|
||||
|
||||
ast_config_destroy(config);
|
||||
@@ -2517,7 +2521,36 @@ struct ast_config *ast_config_load2(const char *filename, const char *who_asked,
|
||||
return result;
|
||||
}
|
||||
|
||||
static struct ast_variable *ast_load_realtime_helper(const char *family, va_list ap)
|
||||
static struct ast_variable *realtime_arguments_to_fields(va_list ap)
|
||||
{
|
||||
struct ast_variable *first, *fields = NULL;
|
||||
const char *newparam = va_arg(ap, const char *), *newval = va_arg(ap, const char *);
|
||||
|
||||
if (!(first = ast_variable_new(newparam, newval, ""))) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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);
|
||||
ast_variables_destroy(first);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
field->next = fields;
|
||||
fields = field;
|
||||
}
|
||||
|
||||
first->next = fields;
|
||||
fields = first;
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
struct ast_variable *ast_load_realtime_all_fields(const char *family, const struct ast_variable *fields)
|
||||
{
|
||||
struct ast_config_engine *eng;
|
||||
char db[256];
|
||||
@@ -2527,7 +2560,7 @@ static struct ast_variable *ast_load_realtime_helper(const char *family, va_list
|
||||
|
||||
for (i = 1; ; i++) {
|
||||
if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
|
||||
if (eng->realtime_func && (res = eng->realtime_func(db, table, ap))) {
|
||||
if (eng->realtime_func && (res = eng->realtime_func(db, table, fields))) {
|
||||
return res;
|
||||
}
|
||||
} else {
|
||||
@@ -2540,26 +2573,28 @@ static struct ast_variable *ast_load_realtime_helper(const char *family, va_list
|
||||
|
||||
struct ast_variable *ast_load_realtime_all(const char *family, ...)
|
||||
{
|
||||
struct ast_variable *res;
|
||||
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
|
||||
struct ast_variable *res = NULL;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
res = ast_load_realtime_helper(family, ap);
|
||||
fields = realtime_arguments_to_fields(ap);
|
||||
va_end(ap);
|
||||
|
||||
if (fields) {
|
||||
res = ast_load_realtime_all_fields(family, fields);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct ast_variable *ast_load_realtime(const char *family, ...)
|
||||
struct ast_variable *ast_load_realtime_fields(const char *family, const struct ast_variable *fields)
|
||||
{
|
||||
struct ast_variable *res;
|
||||
struct ast_variable *cur;
|
||||
struct ast_variable **prev;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
res = ast_load_realtime_helper(family, ap);
|
||||
va_end(ap);
|
||||
res = ast_load_realtime_all_fields(family, fields);
|
||||
|
||||
/* Filter the list. */
|
||||
prev = &res;
|
||||
@@ -2588,6 +2623,18 @@ struct ast_variable *ast_load_realtime(const char *family, ...)
|
||||
return res;
|
||||
}
|
||||
|
||||
struct ast_variable *ast_load_realtime(const char *family, ...)
|
||||
{
|
||||
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
fields = realtime_arguments_to_fields(ap);
|
||||
va_end(ap);
|
||||
|
||||
return ast_load_realtime_fields(family, fields);
|
||||
}
|
||||
|
||||
/*! \brief Check if realtime engine is configured for family */
|
||||
int ast_check_realtime(const char *family)
|
||||
{
|
||||
@@ -2652,19 +2699,17 @@ int ast_unload_realtime(const char *family)
|
||||
return res;
|
||||
}
|
||||
|
||||
struct ast_config *ast_load_realtime_multientry(const char *family, ...)
|
||||
struct ast_config *ast_load_realtime_multientry_fields(const char *family, const struct ast_variable *fields)
|
||||
{
|
||||
struct ast_config_engine *eng;
|
||||
char db[256];
|
||||
char table[256];
|
||||
struct ast_config *res = NULL;
|
||||
va_list ap;
|
||||
int i;
|
||||
|
||||
va_start(ap, family);
|
||||
for (i = 1; ; i++) {
|
||||
if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
|
||||
if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, ap))) {
|
||||
if (eng->realtime_multi_func && (res = eng->realtime_multi_func(db, table, fields))) {
|
||||
/* If we were returned an empty cfg, destroy it and return NULL */
|
||||
if (!res->root) {
|
||||
ast_config_destroy(res);
|
||||
@@ -2676,103 +2721,152 @@ struct ast_config *ast_load_realtime_multientry(const char *family, ...)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
struct ast_config *ast_load_realtime_multientry(const char *family, ...)
|
||||
{
|
||||
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
fields = realtime_arguments_to_fields(ap);
|
||||
va_end(ap);
|
||||
|
||||
return ast_load_realtime_multientry_fields(family, fields);
|
||||
}
|
||||
|
||||
int ast_update_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
|
||||
{
|
||||
struct ast_config_engine *eng;
|
||||
int res = -1, i;
|
||||
char db[256];
|
||||
char table[256];
|
||||
|
||||
for (i = 1; ; i++) {
|
||||
if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
|
||||
/* If the update succeeds, it returns 0. */
|
||||
if (eng->update_func && !(res = eng->update_func(db, table, keyfield, lookup, fields))) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup, ...)
|
||||
{
|
||||
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, lookup);
|
||||
fields = realtime_arguments_to_fields(ap);
|
||||
va_end(ap);
|
||||
|
||||
return ast_update_realtime_fields(family, keyfield, lookup, fields);
|
||||
}
|
||||
|
||||
int ast_update2_realtime_fields(const char *family, const struct ast_variable *lookup_fields, const struct ast_variable *update_fields)
|
||||
{
|
||||
struct ast_config_engine *eng;
|
||||
int res = -1, i;
|
||||
char db[256];
|
||||
char table[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, lookup);
|
||||
for (i = 1; ; i++) {
|
||||
if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
|
||||
/* If the update succeeds, it returns 0. */
|
||||
if (eng->update_func && !(res = eng->update_func(db, table, keyfield, lookup, ap))) {
|
||||
if (eng->update2_func && !(res = eng->update2_func(db, table, lookup_fields, update_fields))) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_update2_realtime(const char *family, ...)
|
||||
{
|
||||
RAII_VAR(struct ast_variable *, lookup_fields, NULL, ast_variables_destroy);
|
||||
RAII_VAR(struct ast_variable *, update_fields, NULL, ast_variables_destroy);
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
lookup_fields = realtime_arguments_to_fields(ap);
|
||||
update_fields = realtime_arguments_to_fields(ap);
|
||||
va_end(ap);
|
||||
|
||||
return ast_update2_realtime_fields(family, lookup_fields, update_fields);
|
||||
}
|
||||
|
||||
int ast_store_realtime_fields(const char *family, const struct ast_variable *fields)
|
||||
{
|
||||
struct ast_config_engine *eng;
|
||||
int res = -1, i;
|
||||
char db[256];
|
||||
char table[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
for (i = 1; ; i++) {
|
||||
if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
|
||||
if (eng->update2_func && !(res = eng->update2_func(db, table, ap))) {
|
||||
/* If the store succeeds, it returns 0. */
|
||||
if (eng->store_func && !(res = eng->store_func(db, table, fields))) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_store_realtime(const char *family, ...)
|
||||
{
|
||||
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
fields = realtime_arguments_to_fields(ap);
|
||||
va_end(ap);
|
||||
|
||||
return ast_store_realtime_fields(family, fields);
|
||||
}
|
||||
|
||||
int ast_destroy_realtime_fields(const char *family, const char *keyfield, const char *lookup, const struct ast_variable *fields)
|
||||
{
|
||||
struct ast_config_engine *eng;
|
||||
int res = -1, i;
|
||||
char db[256];
|
||||
char table[256];
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, family);
|
||||
for (i = 1; ; i++) {
|
||||
if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
|
||||
/* If the store succeeds, it returns 0. */
|
||||
if (eng->store_func && !(res = eng->store_func(db, table, ap))) {
|
||||
if (eng->destroy_func && !(res = eng->destroy_func(db, table, keyfield, lookup, fields))) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup, ...)
|
||||
{
|
||||
struct ast_config_engine *eng;
|
||||
int res = -1, i;
|
||||
char db[256];
|
||||
char table[256];
|
||||
RAII_VAR(struct ast_variable *, fields, NULL, ast_variables_destroy);
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, lookup);
|
||||
for (i = 1; ; i++) {
|
||||
if ((eng = find_engine(family, i, db, sizeof(db), table, sizeof(table)))) {
|
||||
if (eng->destroy_func && !(res = eng->destroy_func(db, table, keyfield, lookup, ap))) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
fields = realtime_arguments_to_fields(ap);
|
||||
va_end(ap);
|
||||
|
||||
return res;
|
||||
return ast_destroy_realtime_fields(family, keyfield, lookup, fields);
|
||||
}
|
||||
|
||||
char *ast_realtime_decode_chunk(char *chunk)
|
||||
|
@@ -540,7 +540,7 @@ int __ast_sorcery_object_field_register(struct ast_sorcery *sorcery, const char
|
||||
int pos;
|
||||
va_list args;
|
||||
|
||||
if (!object_type || !object_type->type.item_alloc) {
|
||||
if (!strcmp(type, "id") || !object_type || !object_type->type.item_alloc) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@@ -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, ")}");
|
||||
|
@@ -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 */
|
||||
|
@@ -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;
|
||||
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_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 *);
|
||||
}
|
||||
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);
|
||||
|
@@ -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));
|
||||
}
|
||||
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
252
res/res_sorcery_realtime.c
Normal file
252
res/res_sorcery_realtime.c
Normal file
@@ -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,
|
||||
);
|
791
tests/test_sorcery_realtime.c
Normal file
791
tests/test_sorcery_realtime.c
Normal file
@@ -0,0 +1,791 @@
|
||||
/*
|
||||
* 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 Unit Tests
|
||||
*
|
||||
* \author Joshua Colp <jcolp@digium.com>
|
||||
*
|
||||
*/
|
||||
|
||||
/*** MODULEINFO
|
||||
<depend>TEST_FRAMEWORK</depend>
|
||||
<support_level>core</support_level>
|
||||
***/
|
||||
|
||||
#include "asterisk.h"
|
||||
|
||||
ASTERISK_FILE_VERSION(__FILE__, "")
|
||||
|
||||
#include "asterisk/test.h"
|
||||
#include "asterisk/module.h"
|
||||
#include "asterisk/sorcery.h"
|
||||
#include "asterisk/astdb.h"
|
||||
#include "asterisk/logger.h"
|
||||
|
||||
/*! \brief Configuration structure which contains all stored objects */
|
||||
static struct ast_config *realtime_objects;
|
||||
|
||||
/*! \brief Helper function which finds a given variable */
|
||||
static const struct ast_variable *realtime_find_variable(const struct ast_variable *fields, const char *name)
|
||||
{
|
||||
const struct ast_variable *variable;
|
||||
|
||||
for (variable = fields; variable; variable = variable->next) {
|
||||
if (!strcmp(variable->name, name)) {
|
||||
return variable;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*! \brief Helper function which returns if an object is matching or not */
|
||||
static int realtime_is_object_matching(const char *object_id, const struct ast_variable *fields)
|
||||
{
|
||||
const struct ast_variable *field;
|
||||
|
||||
for (field = fields; field; field = field->next) {
|
||||
char *name = ast_strdupa(field->name), *like;
|
||||
const char *value;
|
||||
|
||||
/* If we are doing a pattern matching we need to remove the LIKE from the name */
|
||||
if ((like = strstr(name, " LIKE"))) {
|
||||
char *pattern, *field_value = ast_strdupa(field->value);
|
||||
|
||||
*like = '\0';
|
||||
|
||||
value = ast_strdupa(ast_variable_retrieve(realtime_objects, object_id, name));
|
||||
|
||||
if (!(pattern = strchr(field_value, '%'))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
*pattern = '\0';
|
||||
|
||||
if (strncmp(value, field_value, strlen(field_value))) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
value = ast_variable_retrieve(realtime_objects, object_id, name);
|
||||
|
||||
if (ast_strlen_zero(value) || strcmp(value, field->value)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct ast_variable *realtime_sorcery(const char *database, const char *table, const struct ast_variable *fields)
|
||||
{
|
||||
char *object_id = NULL;
|
||||
|
||||
while ((object_id = ast_category_browse(realtime_objects, object_id))) {
|
||||
if (!realtime_is_object_matching(object_id, fields)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return ast_variables_dup(ast_category_root(realtime_objects, object_id));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ast_config *realtime_sorcery_multi(const char *database, const char *table, const struct ast_variable *fields)
|
||||
{
|
||||
struct ast_config *objects;
|
||||
char *object_id = NULL;
|
||||
|
||||
if (!(objects = ast_config_new())) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while ((object_id = ast_category_browse(realtime_objects, object_id))) {
|
||||
struct ast_category *object;
|
||||
|
||||
if (!realtime_is_object_matching(object_id, fields)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(object = ast_category_new("", "", 0))) {
|
||||
ast_config_destroy(objects);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_variable_append(object, ast_variables_dup(ast_category_root(realtime_objects, object_id)));
|
||||
ast_category_append(objects, object);
|
||||
}
|
||||
|
||||
return objects;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (!ast_category_exist(realtime_objects, entity)) {
|
||||
return 0;
|
||||
} else if (!(object = ast_category_new(entity, "", 0))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_category_delete(realtime_objects, entity);
|
||||
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 realtime_sorcery_store(const char *database, const char *table, const struct ast_variable *fields)
|
||||
{
|
||||
/* The key field is explicit within res_sorcery_realtime */
|
||||
const struct ast_variable *keyfield = realtime_find_variable(fields, "id");
|
||||
struct ast_category *object;
|
||||
|
||||
if (!keyfield || ast_category_exist(realtime_objects, keyfield->value) || !(object = ast_category_new(keyfield->value, "", 0))) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_variable_append(object, ast_variables_dup((struct ast_variable*)fields));
|
||||
ast_category_append(realtime_objects, object);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int realtime_sorcery_destroy(const char *database, const char *table, const char *keyfield, const char *entity, const struct ast_variable *fields)
|
||||
{
|
||||
if (!ast_category_exist(realtime_objects, entity)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast_category_delete(realtime_objects, entity);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct ast_config_engine sorcery_config_engine = {
|
||||
.name = "sorcery_realtime_test",
|
||||
.realtime_func = realtime_sorcery,
|
||||
.realtime_multi_func = realtime_sorcery_multi,
|
||||
.update_func = realtime_sorcery_update,
|
||||
.store_func = realtime_sorcery_store,
|
||||
.destroy_func = realtime_sorcery_destroy,
|
||||
};
|
||||
|
||||
/*! \brief Dummy sorcery object */
|
||||
struct test_sorcery_object {
|
||||
SORCERY_OBJECT(details);
|
||||
unsigned int bob;
|
||||
unsigned int joe;
|
||||
};
|
||||
|
||||
/*! \brief Internal function to allocate a test object */
|
||||
static void *test_sorcery_object_alloc(const char *id)
|
||||
{
|
||||
return ao2_alloc(sizeof(struct test_sorcery_object), NULL);
|
||||
}
|
||||
|
||||
static struct ast_sorcery *alloc_and_initialize_sorcery(void)
|
||||
{
|
||||
struct ast_sorcery *sorcery;
|
||||
|
||||
if (!(sorcery = ast_sorcery_open())) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_apply_default(sorcery, "test", "realtime", "sorcery_realtime_test") ||
|
||||
ast_sorcery_object_register(sorcery, "test", test_sorcery_object_alloc, NULL, NULL) ||
|
||||
!(realtime_objects = ast_config_new())) {
|
||||
ast_sorcery_unref(sorcery);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ast_sorcery_object_field_register(sorcery, "test", "bob", "5", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, bob));
|
||||
ast_sorcery_object_field_register(sorcery, "test", "joe", "10", OPT_UINT_T, 0, FLDSET(struct test_sorcery_object, joe));
|
||||
|
||||
return sorcery;
|
||||
}
|
||||
|
||||
static void deinitialize_sorcery(struct ast_sorcery *sorcery)
|
||||
{
|
||||
ast_config_destroy(realtime_objects);
|
||||
realtime_objects = NULL;
|
||||
ast_sorcery_unref(sorcery);
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_create)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_create";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery realtime object creation unit test";
|
||||
info->description =
|
||||
"Test object creation in sorcery using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_retrieve_id)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_retrieve_id";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery object retrieval using id unit test";
|
||||
info->description =
|
||||
"Test object retrieval using id in sorcery with realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using astdb wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
|
||||
ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to retrieve properly created object using id of 'blah'\n");
|
||||
return AST_TEST_FAIL;
|
||||
} else if (strcmp(ast_sorcery_object_get_id(obj), "blah")) {
|
||||
ast_test_status_update(test, "Retrieved object does not have correct id\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_retrieve_field)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "42", ""), ast_variables_destroy);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_retrieve_field";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery object retrieval using a specific field unit test";
|
||||
info->description =
|
||||
"Test object retrieval using a specific field in sorcery with realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fields) {
|
||||
ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
obj->joe = 42;
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
if (!(obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
|
||||
ast_test_status_update(test, "Failed to retrieve properly created object using 'joe' field\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
ast_variables_destroy(fields);
|
||||
|
||||
if (!(fields = ast_variable_new("joe", "49", ""))) {
|
||||
ast_test_status_update(test, "Failed to create fields for object retrieval attempt\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if ((obj = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_DEFAULT, fields))) {
|
||||
ast_test_status_update(test, "Retrieved an object using a field with an in-correct value... that should not happen\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_retrieve_multiple_all)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_retrieve_multiple_all";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery multiple object retrieval unit test";
|
||||
info->description =
|
||||
"Test multiple object retrieval in sorcery using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah2"))) {
|
||||
ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create second object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL))) {
|
||||
ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
|
||||
return AST_TEST_FAIL;
|
||||
} else if (ao2_container_count(objects) != 2) {
|
||||
ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_retrieve_multiple_field)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ast_variable *, fields, ast_variable_new("joe", "6", ""), ast_variables_destroy);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_retrieve_multiple_field";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery multiple object retrieval unit test";
|
||||
info->description =
|
||||
"Test multiple object retrieval in sorcery using fields using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!fields) {
|
||||
ast_test_status_update(test, "Failed to create fields for multiple retrieve\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
obj->joe = 6;
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
|
||||
ast_test_status_update(test, "Failed to retrieve a container of all objects\n");
|
||||
return AST_TEST_FAIL;
|
||||
} else if (ao2_container_count(objects) != 1) {
|
||||
ast_test_status_update(test, "Received a container with no objects in it when there should be some\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(objects);
|
||||
ast_variables_destroy(fields);
|
||||
|
||||
if (!(fields = ast_variable_new("joe", "7", ""))) {
|
||||
ast_test_status_update(test, "Failed to create fields for multiple retrieval\n");
|
||||
return AST_TEST_FAIL;
|
||||
} else if (!(objects = ast_sorcery_retrieve_by_fields(sorcery, "test", AST_RETRIEVE_FLAG_MULTIPLE, fields))) {
|
||||
ast_test_status_update(test, "Failed to retrieve an empty container when retrieving multiple\n");
|
||||
return AST_TEST_FAIL;
|
||||
} else if (ao2_container_count(objects)) {
|
||||
ast_test_status_update(test, "Received a container with objects when there should be none in it\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_retrieve_regex)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_retrieve_regex";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery multiple object retrieval using regex unit test";
|
||||
info->description =
|
||||
"Test multiple object retrieval in sorcery using regular expression for matching using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-98joe"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah-93joe"))) {
|
||||
ast_test_status_update(test, "Failed to allocate second instance of a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create second object using astdb wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "neener-93joe"))) {
|
||||
ast_test_status_update(test, "Failed to allocate third instance of a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create third object using astdb wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(objects = ast_sorcery_retrieve_by_regex(sorcery, "test", "^blah-"))) {
|
||||
ast_test_status_update(test, "Failed to retrieve a container of objects\n");
|
||||
return AST_TEST_FAIL;
|
||||
} else if (ao2_container_count(objects) != 2) {
|
||||
ast_test_status_update(test, "Received a container with incorrect number of objects in it\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_update)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
RAII_VAR(struct test_sorcery_object *, obj2, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_update";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery object update unit test";
|
||||
info->description =
|
||||
"Test object updating in sorcery using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj2 = ast_sorcery_copy(sorcery, obj))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type for updating\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
obj2->bob = 1000;
|
||||
obj2->joe = 2000;
|
||||
|
||||
if (ast_sorcery_update(sorcery, obj2)) {
|
||||
ast_test_status_update(test, "Failed to update sorcery with new object\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to retrieve properly updated object\n");
|
||||
return AST_TEST_FAIL;
|
||||
} else if ((obj->bob != obj2->bob) || (obj->joe != obj2->joe)) {
|
||||
ast_test_status_update(test, "Object retrieved is not the updated object\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_update_uncreated)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_update_uncreated";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery object update unit test";
|
||||
info->description =
|
||||
"Test updating of an uncreated object in sorcery using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!ast_sorcery_update(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Successfully updated an object which has not been created yet\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_delete)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_delete";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery object deletion unit test";
|
||||
info->description =
|
||||
"Test object deletion in sorcery using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_create(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to create object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (ast_sorcery_delete(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Failed to delete object using realtime wizard\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
ao2_cleanup(obj);
|
||||
|
||||
if ((obj = ast_sorcery_retrieve_by_id(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Retrieved deleted object that should not be there\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
AST_TEST_DEFINE(object_delete_uncreated)
|
||||
{
|
||||
RAII_VAR(struct ast_sorcery *, sorcery, NULL, deinitialize_sorcery);
|
||||
RAII_VAR(struct test_sorcery_object *, obj, NULL, ao2_cleanup);
|
||||
|
||||
switch (cmd) {
|
||||
case TEST_INIT:
|
||||
info->name = "object_delete_uncreated";
|
||||
info->category = "/res/sorcery_realtime/";
|
||||
info->summary = "sorcery object deletion unit test";
|
||||
info->description =
|
||||
"Test object deletion of an uncreated object in sorcery using realtime wizard";
|
||||
return AST_TEST_NOT_RUN;
|
||||
case TEST_EXECUTE:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(sorcery = alloc_and_initialize_sorcery())) {
|
||||
ast_test_status_update(test, "Failed to open sorcery structure\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!(obj = ast_sorcery_alloc(sorcery, "test", "blah"))) {
|
||||
ast_test_status_update(test, "Failed to allocate a known object type\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
if (!ast_sorcery_delete(sorcery, obj)) {
|
||||
ast_test_status_update(test, "Successfully deleted an object which was never created\n");
|
||||
return AST_TEST_FAIL;
|
||||
}
|
||||
|
||||
return AST_TEST_PASS;
|
||||
}
|
||||
|
||||
static int unload_module(void)
|
||||
{
|
||||
ast_config_engine_deregister(&sorcery_config_engine);
|
||||
AST_TEST_UNREGISTER(object_create);
|
||||
AST_TEST_UNREGISTER(object_retrieve_id);
|
||||
AST_TEST_UNREGISTER(object_retrieve_field);
|
||||
AST_TEST_UNREGISTER(object_retrieve_multiple_all);
|
||||
AST_TEST_UNREGISTER(object_retrieve_multiple_field);
|
||||
AST_TEST_UNREGISTER(object_retrieve_regex);
|
||||
AST_TEST_UNREGISTER(object_update);
|
||||
AST_TEST_UNREGISTER(object_update_uncreated);
|
||||
AST_TEST_UNREGISTER(object_delete);
|
||||
AST_TEST_UNREGISTER(object_delete_uncreated);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_module(void)
|
||||
{
|
||||
ast_config_engine_register(&sorcery_config_engine);
|
||||
ast_realtime_append_mapping("sorcery_realtime_test", "sorcery_realtime_test", "test", "test", 1);
|
||||
AST_TEST_REGISTER(object_create);
|
||||
AST_TEST_REGISTER(object_retrieve_id);
|
||||
AST_TEST_REGISTER(object_retrieve_field);
|
||||
AST_TEST_REGISTER(object_retrieve_multiple_all);
|
||||
AST_TEST_REGISTER(object_retrieve_multiple_field);
|
||||
AST_TEST_REGISTER(object_retrieve_regex);
|
||||
AST_TEST_REGISTER(object_update);
|
||||
AST_TEST_REGISTER(object_update_uncreated);
|
||||
AST_TEST_REGISTER(object_delete);
|
||||
AST_TEST_REGISTER(object_delete_uncreated);
|
||||
|
||||
return AST_MODULE_LOAD_SUCCESS;
|
||||
}
|
||||
|
||||
AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Sorcery Realtime Wizard test module");
|
Reference in New Issue
Block a user