aboutsummaryrefslogtreecommitdiffstats
path: root/1.4.23-rc4/funcs/func_odbc.c
diff options
context:
space:
mode:
Diffstat (limited to '1.4.23-rc4/funcs/func_odbc.c')
-rw-r--r--1.4.23-rc4/funcs/func_odbc.c672
1 files changed, 0 insertions, 672 deletions
diff --git a/1.4.23-rc4/funcs/func_odbc.c b/1.4.23-rc4/funcs/func_odbc.c
deleted file mode 100644
index 49007d792..000000000
--- a/1.4.23-rc4/funcs/func_odbc.c
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- * Asterisk -- An open source telephony toolkit.
- *
- * Copyright (c) 2005, 2006 Tilghman Lesher
- *
- * Tilghman Lesher <func_odbc__200508@the-tilghman.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 ODBC lookups
- *
- * \author Tilghman Lesher <func_odbc__200508@the-tilghman.com>
- */
-
-/*** MODULEINFO
- <depend>unixodbc</depend>
- <depend>ltdl</depend>
- <depend>res_odbc</depend>
- ***/
-
-#include "asterisk.h"
-
-ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-
-#include "asterisk/module.h"
-#include "asterisk/file.h"
-#include "asterisk/logger.h"
-#include "asterisk/options.h"
-#include "asterisk/channel.h"
-#include "asterisk/pbx.h"
-#include "asterisk/module.h"
-#include "asterisk/config.h"
-#include "asterisk/res_odbc.h"
-#include "asterisk/app.h"
-
-static char *config = "func_odbc.conf";
-
-enum {
- OPT_ESCAPECOMMAS = (1 << 0),
-} odbc_option_flags;
-
-struct acf_odbc_query {
- AST_LIST_ENTRY(acf_odbc_query) list;
- char dsn[30];
- char sql_read[2048];
- char sql_write[2048];
- unsigned int flags;
- struct ast_custom_function *acf;
-};
-
-AST_LIST_HEAD_STATIC(queries, acf_odbc_query);
-
-static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
-{
- int res;
- char *sql = data;
- SQLHSTMT stmt;
-
- res = SQLAllocHandle (SQL_HANDLE_STMT, obj->con, &stmt);
- if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
- ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
- return NULL;
- }
-
- res = SQLPrepare(stmt, (unsigned char *)sql, SQL_NTS);
- if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
- ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
- SQLCloseCursor(stmt);
- SQLFreeHandle (SQL_HANDLE_STMT, stmt);
- return NULL;
- }
-
- return stmt;
-}
-
-/*
- * Master control routine
- */
-static int acf_odbc_write(struct ast_channel *chan, char *cmd, char *s, const char *value)
-{
- struct odbc_obj *obj;
- struct acf_odbc_query *query;
- char *t, buf[2048]="", varname[15];
- int i, bogus_chan = 0;
- AST_DECLARE_APP_ARGS(values,
- AST_APP_ARG(field)[100];
- );
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(field)[100];
- );
- SQLHSTMT stmt;
- SQLLEN rows=0;
-
- AST_LIST_LOCK(&queries);
- AST_LIST_TRAVERSE(&queries, query, list) {
- if (!strcmp(query->acf->name, cmd)) {
- break;
- }
- }
-
- if (!query) {
- ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
- AST_LIST_UNLOCK(&queries);
- return -1;
- }
-
- obj = ast_odbc_request_obj(query->dsn, 0);
-
- if (!obj) {
- ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", query->dsn);
- AST_LIST_UNLOCK(&queries);
- return -1;
- }
-
- if (!chan) {
- if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc")))
- bogus_chan = 1;
- }
-
- if (chan)
- ast_autoservice_start(chan);
-
- /* Parse our arguments */
- t = value ? ast_strdupa(value) : "";
-
- if (!s || !t) {
- ast_log(LOG_ERROR, "Out of memory\n");
- AST_LIST_UNLOCK(&queries);
- if (chan)
- ast_autoservice_stop(chan);
- if (bogus_chan)
- ast_channel_free(chan);
- return -1;
- }
-
- AST_STANDARD_APP_ARGS(args, s);
- for (i = 0; i < args.argc; i++) {
- snprintf(varname, sizeof(varname), "ARG%d", i + 1);
- pbx_builtin_pushvar_helper(chan, varname, args.field[i]);
- }
-
- /* Parse values, just like arguments */
- /* Can't use the pipe, because app Set removes them */
- AST_NONSTANDARD_APP_ARGS(values, t, ',');
- for (i = 0; i < values.argc; i++) {
- snprintf(varname, sizeof(varname), "VAL%d", i + 1);
- pbx_builtin_pushvar_helper(chan, varname, values.field[i]);
- }
-
- /* Additionally set the value as a whole (but push an empty string if value is NULL) */
- pbx_builtin_pushvar_helper(chan, "VALUE", value ? value : "");
-
- pbx_substitute_variables_helper(chan, query->sql_write, buf, sizeof(buf) - 1);
-
- /* Restore prior values */
- for (i = 0; i < args.argc; i++) {
- snprintf(varname, sizeof(varname), "ARG%d", i + 1);
- pbx_builtin_setvar_helper(chan, varname, NULL);
- }
-
- for (i = 0; i < values.argc; i++) {
- snprintf(varname, sizeof(varname), "VAL%d", i + 1);
- pbx_builtin_setvar_helper(chan, varname, NULL);
- }
- pbx_builtin_setvar_helper(chan, "VALUE", NULL);
-
- AST_LIST_UNLOCK(&queries);
-
- stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, buf);
-
- if (stmt) {
- /* Rows affected */
- SQLRowCount(stmt, &rows);
- }
-
- /* Output the affected rows, for all cases. In the event of failure, we
- * flag this as -1 rows. Note that this is different from 0 affected rows
- * which would be the case if we succeeded in our query, but the values did
- * not change. */
- snprintf(varname, sizeof(varname), "%d", (int)rows);
- pbx_builtin_setvar_helper(chan, "ODBCROWS", varname);
-
- if (stmt) {
- SQLCloseCursor(stmt);
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- }
- if (obj)
- ast_odbc_release_obj(obj);
-
- if (chan)
- ast_autoservice_stop(chan);
- if (bogus_chan)
- ast_channel_free(chan);
-
- return 0;
-}
-
-static int acf_odbc_read(struct ast_channel *chan, char *cmd, char *s, char *buf, size_t len)
-{
- struct odbc_obj *obj;
- struct acf_odbc_query *query;
- char sql[2048] = "", varname[15];
- int res, x, buflen = 1, escapecommas, bogus_chan = 0;
- AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(field)[100];
- );
- SQLHSTMT stmt;
- SQLSMALLINT colcount=0;
- SQLLEN indicator;
-
- AST_LIST_LOCK(&queries);
- AST_LIST_TRAVERSE(&queries, query, list) {
- if (!strcmp(query->acf->name, cmd)) {
- break;
- }
- }
-
- if (!query) {
- ast_log(LOG_ERROR, "No such function '%s'\n", cmd);
- AST_LIST_UNLOCK(&queries);
- return -1;
- }
-
- obj = ast_odbc_request_obj(query->dsn, 0);
-
- if (!obj) {
- ast_log(LOG_ERROR, "No such DSN registered (or out of connections): %s (check res_odbc.conf)\n", query->dsn);
- AST_LIST_UNLOCK(&queries);
- return -1;
- }
-
- if (!chan) {
- if ((chan = ast_channel_alloc(0, 0, "", "", "", "", "", 0, "Bogus/func_odbc")))
- bogus_chan = 1;
- }
-
- if (chan)
- ast_autoservice_start(chan);
-
- AST_STANDARD_APP_ARGS(args, s);
- for (x = 0; x < args.argc; x++) {
- snprintf(varname, sizeof(varname), "ARG%d", x + 1);
- pbx_builtin_pushvar_helper(chan, varname, args.field[x]);
- }
-
- pbx_substitute_variables_helper(chan, query->sql_read, sql, sizeof(sql) - 1);
-
- /* Restore prior values */
- for (x = 0; x < args.argc; x++) {
- snprintf(varname, sizeof(varname), "ARG%d", x + 1);
- pbx_builtin_setvar_helper(chan, varname, NULL);
- }
-
- /* Save this flag, so we can release the lock */
- escapecommas = ast_test_flag(query, OPT_ESCAPECOMMAS);
-
- AST_LIST_UNLOCK(&queries);
-
- stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, sql);
-
- if (!stmt) {
- ast_odbc_release_obj(obj);
- if (chan)
- ast_autoservice_stop(chan);
- if (bogus_chan)
- ast_channel_free(chan);
- return -1;
- }
-
- res = SQLNumResultCols(stmt, &colcount);
- if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
- ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
- SQLCloseCursor(stmt);
- SQLFreeHandle (SQL_HANDLE_STMT, stmt);
- ast_odbc_release_obj(obj);
- if (chan)
- ast_autoservice_stop(chan);
- if (bogus_chan)
- ast_channel_free(chan);
- return -1;
- }
-
- *buf = '\0';
-
- res = SQLFetch(stmt);
- if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
- int res1 = -1;
- if (res == SQL_NO_DATA) {
- if (option_verbose > 3) {
- ast_verbose(VERBOSE_PREFIX_4 "Found no rows [%s]\n", sql);
- }
- res1 = 0;
- } else if (option_verbose > 3) {
- ast_log(LOG_WARNING, "Error %d in FETCH [%s]\n", res, sql);
- }
- SQLCloseCursor(stmt);
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- ast_odbc_release_obj(obj);
- if (chan)
- ast_autoservice_stop(chan);
- if (bogus_chan)
- ast_channel_free(chan);
- return res1;
- }
-
- for (x = 0; x < colcount; x++) {
- int i;
- char coldata[256];
-
- buflen = strlen(buf);
- res = SQLGetData(stmt, x + 1, SQL_CHAR, coldata, sizeof(coldata), &indicator);
- if (indicator == SQL_NULL_DATA) {
- coldata[0] = '\0';
- res = SQL_SUCCESS;
- }
-
- if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
- ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
- SQLCloseCursor(stmt);
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- ast_odbc_release_obj(obj);
- if (chan)
- ast_autoservice_stop(chan);
- if (bogus_chan)
- ast_channel_free(chan);
- return -1;
- }
-
- /* Copy data, encoding '\' and ',' for the argument parser */
- for (i = 0; i < sizeof(coldata); i++) {
- if (escapecommas && (coldata[i] == '\\' || coldata[i] == ',')) {
- buf[buflen++] = '\\';
- }
- buf[buflen++] = coldata[i];
-
- if (buflen >= len - 2)
- break;
-
- if (coldata[i] == '\0')
- break;
- }
-
- buf[buflen - 1] = ',';
- buf[buflen] = '\0';
- }
- /* Trim trailing comma */
- buf[buflen - 1] = '\0';
-
- SQLCloseCursor(stmt);
- SQLFreeHandle(SQL_HANDLE_STMT, stmt);
- ast_odbc_release_obj(obj);
- if (chan)
- ast_autoservice_stop(chan);
- if (bogus_chan)
- ast_channel_free(chan);
- return 0;
-}
-
-static int acf_escape(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len)
-{
- char *out = buf;
-
- for (; *data && out - buf < len; data++) {
- if (*data == '\'') {
- *out = '\'';
- out++;
- }
- *out++ = *data;
- }
- *out = '\0';
-
- return 0;
-}
-
-static struct ast_custom_function escape_function = {
- .name = "SQL_ESC",
- .synopsis = "Escapes single ticks for use in SQL statements",
- .syntax = "SQL_ESC(<string>)",
- .desc =
-"Used in SQL templates to escape data which may contain single ticks (') which\n"
-"are otherwise used to delimit data. For example:\n"
-"SELECT foo FROM bar WHERE baz='${SQL_ESC(${ARG1})}'\n",
- .read = acf_escape,
- .write = NULL,
-};
-
-static int init_acf_query(struct ast_config *cfg, char *catg, struct acf_odbc_query **query)
-{
- const char *tmp;
- int res;
-
- if (!cfg || !catg) {
- return -1;
- }
-
- *query = ast_calloc(1, sizeof(struct acf_odbc_query));
- if (! (*query))
- return -1;
-
- if ((tmp = ast_variable_retrieve(cfg, catg, "dsn"))) {
- ast_copy_string((*query)->dsn, tmp, sizeof((*query)->dsn));
- } else if ((tmp = ast_variable_retrieve(cfg, catg, "writehandle")) || (tmp = ast_variable_retrieve(cfg, catg, "readhandle"))) {
- ast_log(LOG_WARNING, "Separate read and write handles are not supported in this version of func_odbc.so\n");
- ast_copy_string((*query)->dsn, tmp, sizeof((*query)->dsn));
- } else {
- free(*query);
- *query = NULL;
- ast_log(LOG_ERROR, "No database handle was specified for func_odbc class '%s'\n", catg);
- return -1;
- }
-
- if ((tmp = ast_variable_retrieve(cfg, catg, "read")) || (tmp = ast_variable_retrieve(cfg, catg, "readsql"))) {
- ast_copy_string((*query)->sql_read, tmp, sizeof((*query)->sql_read));
- }
-
- if ((tmp = ast_variable_retrieve(cfg, catg, "write")) || (tmp = ast_variable_retrieve(cfg, catg, "writesql"))) {
- ast_copy_string((*query)->sql_write, tmp, sizeof((*query)->sql_write));
- }
-
- /* Allow escaping of embedded commas in fields to be turned off */
- ast_set_flag((*query), OPT_ESCAPECOMMAS);
- if ((tmp = ast_variable_retrieve(cfg, catg, "escapecommas"))) {
- if (ast_false(tmp))
- ast_clear_flag((*query), OPT_ESCAPECOMMAS);
- }
-
- (*query)->acf = ast_calloc(1, sizeof(struct ast_custom_function));
- if (! (*query)->acf) {
- free(*query);
- *query = NULL;
- return -1;
- }
-
- if ((tmp = ast_variable_retrieve(cfg, catg, "prefix")) && !ast_strlen_zero(tmp)) {
- if (asprintf((char **)&((*query)->acf->name), "%s_%s", tmp, catg) < 0) {
- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
- }
- } else {
- if (asprintf((char **)&((*query)->acf->name), "ODBC_%s", catg) < 0) {
- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
- }
- }
-
- if (!((*query)->acf->name)) {
- free((*query)->acf);
- free(*query);
- *query = NULL;
- return -1;
- }
-
- if (asprintf((char **)&((*query)->acf->syntax), "%s(<arg1>[...[,<argN>]])", (*query)->acf->name) < 0) {
- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
- (*query)->acf->syntax = NULL;
- }
-
- if (!((*query)->acf->syntax)) {
- free((char *)(*query)->acf->name);
- free((*query)->acf);
- free(*query);
- *query = NULL;
- return -1;
- }
-
- res = 0;
- (*query)->acf->synopsis = "Runs the referenced query with the specified arguments";
- if (!ast_strlen_zero((*query)->sql_read) && !ast_strlen_zero((*query)->sql_write)) {
- res = asprintf((char **)&((*query)->acf->desc),
- "Runs the following query, as defined in func_odbc.conf, performing\n"
- "substitution of the arguments into the query as specified by ${ARG1},\n"
- "${ARG2}, ... ${ARGn}. When setting the function, the values are provided\n"
- "either in whole as ${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
- "\nRead:\n%s\n\nWrite:\n%s\n",
- (*query)->sql_read,
- (*query)->sql_write);
- } else if (!ast_strlen_zero((*query)->sql_read)) {
- res = asprintf((char **)&((*query)->acf->desc),
- "Runs the following query, as defined in func_odbc.conf, performing\n"
- "substitution of the arguments into the query as specified by ${ARG1},\n"
- "${ARG2}, ... ${ARGn}. This function may only be read, not set.\n\nSQL:\n%s\n",
- (*query)->sql_read);
- } else if (!ast_strlen_zero((*query)->sql_write)) {
- res = asprintf((char **)&((*query)->acf->desc),
- "Runs the following query, as defined in func_odbc.conf, performing\n"
- "substitution of the arguments into the query as specified by ${ARG1},\n"
- "${ARG2}, ... ${ARGn}. The values are provided either in whole as\n"
- "${VALUE} or parsed as ${VAL1}, ${VAL2}, ... ${VALn}.\n"
- "This function may only be set.\nSQL:\n%s\n",
- (*query)->sql_write);
- } else {
- ast_log(LOG_ERROR, "No SQL was found for func_odbc class '%s'\n", catg);
- }
-
- if (res < 0) {
- ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
- (*query)->acf->desc = NULL;
- }
-
- /* Could be out of memory, or could be we have neither sql_read nor sql_write */
- if (!((*query)->acf->desc)) {
- free((char *)(*query)->acf->syntax);
- free((char *)(*query)->acf->name);
- free((*query)->acf);
- free(*query);
- *query = NULL;
- return -1;
- }
-
- if (ast_strlen_zero((*query)->sql_read)) {
- (*query)->acf->read = NULL;
- } else {
- (*query)->acf->read = acf_odbc_read;
- }
-
- if (ast_strlen_zero((*query)->sql_write)) {
- (*query)->acf->write = NULL;
- } else {
- (*query)->acf->write = acf_odbc_write;
- }
-
- return 0;
-}
-
-static int free_acf_query(struct acf_odbc_query *query)
-{
- if (query) {
- if (query->acf) {
- if (query->acf->name)
- free((char *)query->acf->name);
- if (query->acf->syntax)
- free((char *)query->acf->syntax);
- if (query->acf->desc)
- free((char *)query->acf->desc);
- free(query->acf);
- }
- free(query);
- }
- return 0;
-}
-
-static int odbc_load_module(void)
-{
- int res = 0;
- struct ast_config *cfg;
- char *catg;
-
- AST_LIST_LOCK(&queries);
-
- cfg = ast_config_load(config);
- if (!cfg) {
- ast_log(LOG_NOTICE, "Unable to load config for func_odbc: %s\n", config);
- AST_LIST_UNLOCK(&queries);
- return AST_MODULE_LOAD_DECLINE;
- }
-
- for (catg = ast_category_browse(cfg, NULL);
- catg;
- catg = ast_category_browse(cfg, catg)) {
- struct acf_odbc_query *query = NULL;
-
- if (init_acf_query(cfg, catg, &query)) {
- free_acf_query(query);
- } else {
- AST_LIST_INSERT_HEAD(&queries, query, list);
- ast_custom_function_register(query->acf);
- }
- }
-
- ast_config_destroy(cfg);
- ast_custom_function_register(&escape_function);
-
- AST_LIST_UNLOCK(&queries);
- return res;
-}
-
-static int odbc_unload_module(void)
-{
- struct acf_odbc_query *query;
-
- AST_LIST_LOCK(&queries);
- while (!AST_LIST_EMPTY(&queries)) {
- query = AST_LIST_REMOVE_HEAD(&queries, list);
- ast_custom_function_unregister(query->acf);
- free_acf_query(query);
- }
-
- ast_custom_function_unregister(&escape_function);
-
- /* Allow any threads waiting for this lock to pass (avoids a race) */
- AST_LIST_UNLOCK(&queries);
- AST_LIST_LOCK(&queries);
-
- AST_LIST_UNLOCK(&queries);
- return 0;
-}
-
-static int reload(void)
-{
- int res = 0;
- struct ast_config *cfg;
- struct acf_odbc_query *oldquery;
- char *catg;
-
- AST_LIST_LOCK(&queries);
-
- while (!AST_LIST_EMPTY(&queries)) {
- oldquery = AST_LIST_REMOVE_HEAD(&queries, list);
- ast_custom_function_unregister(oldquery->acf);
- free_acf_query(oldquery);
- }
-
- cfg = ast_config_load(config);
- if (!cfg) {
- ast_log(LOG_WARNING, "Unable to load config for func_odbc: %s\n", config);
- goto reload_out;
- }
-
- for (catg = ast_category_browse(cfg, NULL);
- catg;
- catg = ast_category_browse(cfg, catg)) {
- struct acf_odbc_query *query = NULL;
-
- if (init_acf_query(cfg, catg, &query)) {
- ast_log(LOG_ERROR, "Cannot initialize query %s\n", catg);
- } else {
- AST_LIST_INSERT_HEAD(&queries, query, list);
- ast_custom_function_register(query->acf);
- }
- }
-
- ast_config_destroy(cfg);
-reload_out:
- AST_LIST_UNLOCK(&queries);
- return res;
-}
-
-static int unload_module(void)
-{
- return odbc_unload_module();
-}
-
-static int load_module(void)
-{
- return odbc_load_module();
-}
-
-/* XXX need to revise usecount - set if query_lock is set */
-
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "ODBC lookups",
- .load = load_module,
- .unload = unload_module,
- .reload = reload,
- );
-