[asterisk-commits] tilghman: trunk r98981 - in /trunk: main/utils.c res/res_config_curl.c

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Jan 16 16:20:46 CST 2008


Author: tilghman
Date: Wed Jan 16 16:20:45 2008
New Revision: 98981

URL: http://svn.digium.com/view/asterisk?view=rev&rev=98981
Log:
New module res_config_curl (closes issue #11747)
 Reported by: Corydon76
 Patches: 
       res_config_curl.c uploaded by Corydon76 (license 14)
       20080116__bug11747.diff.txt uploaded by Corydon76 (license 14)
 Tested by: jmls

Added:
    trunk/res/res_config_curl.c
      - copied, changed from r98483, trunk/res/res_config_odbc.c
Modified:
    trunk/main/utils.c

Modified: trunk/main/utils.c
URL: http://svn.digium.com/view/asterisk/trunk/main/utils.c?view=diff&rev=98981&r1=98980&r2=98981
==============================================================================
--- trunk/main/utils.c (original)
+++ trunk/main/utils.c Wed Jan 16 16:20:45 2008
@@ -451,7 +451,7 @@
 
 	/* If there's no characters to convert, just go through and don't do anything */
 	while (*ptr) {
-		if (((unsigned char) *ptr) > 127 || (doreserved && strchr(reserved, *ptr)) ) {
+		if ((*ptr < 32 || (unsigned char) *ptr) > 127 || (doreserved && strchr(reserved, *ptr)) ) {
 			/* Oops, we need to start working here */
 			if (!buf) {
 				buf = outbuf;

Copied: trunk/res/res_config_curl.c (from r98483, trunk/res/res_config_odbc.c)
URL: http://svn.digium.com/view/asterisk/trunk/res/res_config_curl.c?view=diff&rev=98981&p1=trunk/res/res_config_odbc.c&r1=98483&p2=trunk/res/res_config_curl.c&r2=98981
==============================================================================
--- trunk/res/res_config_odbc.c (original)
+++ trunk/res/res_config_curl.c Wed Jan 16 16:20:45 2008
@@ -1,11 +1,9 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 1999 - 2005, Digium, Inc.
- *
- * Mark Spencer <markster at digium.com>
- *
- * Copyright (C) 2004 - 2005 Anthony Minessale II <anthmct at yahoo.com>
+ * Copyright (C) 1999 - 2008, Digium, Inc.
+ *
+ * Tilghman Lesher <res_config_curl_v1 at the-tilghman.com>
  *
  * See http://www.asterisk.org for more information about
  * the Asterisk project. Please do not directly contact
@@ -20,23 +18,23 @@
 
 /*! \file
  *
- * \brief odbc+odbc plugin for portable configuration engine
- *
- * \author Mark Spencer <markster at digium.com>
- * \author Anthony Minessale II <anthmct at yahoo.com>
- *
- * \arg http://www.unixodbc.org
+ * \brief curl plugin for portable configuration engine
+ *
+ * \author Tilghman Lesher <res_config_curl_v1 at the-tilghman.com>
+ *
+ * \extref Depends on the CURL library  - http://curl.haxx.se/
+ * 
  */
 
 /*** MODULEINFO
-	<depend>unixodbc</depend>
-	<depend>ltdl</depend>
-	<depend>res_odbc</depend>
+	<depend>curl</depend>
  ***/
 
 #include "asterisk.h"
 
 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <curl/curl.h>
 
 #include "asterisk/file.h"
 #include "asterisk/channel.h"
@@ -44,342 +42,170 @@
 #include "asterisk/config.h"
 #include "asterisk/module.h"
 #include "asterisk/lock.h"
-#include "asterisk/res_odbc.h"
 #include "asterisk/utils.h"
 
-struct custom_prepare_struct {
-	const char *sql;
-	const char *extra;
-	va_list ap;
-};
-
-static SQLHSTMT custom_prepare(struct odbc_obj *obj, void *data)
-{
-	int res, x = 1;
-	struct custom_prepare_struct *cps = data;
-	const char *newparam, *newval;
-	SQLHSTMT stmt;
-	va_list ap;
-
-	va_copy(ap, cps->ap);
-
-	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 *)cps->sql, SQL_NTS);
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", cps->sql);
-		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-		return NULL;
-	}
-
-	while ((newparam = va_arg(ap, const char *))) {
-		newval = va_arg(ap, const char *);
-		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);
-	return stmt;
-}
-
 /*!
- * \brief Excute an SQL query and return ast_variable list
- * \param database
- * \param table
+ * \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.
- *
- * Select database and preform query on table, prepare the sql statement
- * Sub-in the values to the prepared statement and execute it. Return results
- * as a ast_variable list.
  *
  * \retval var on success
  * \retval NULL on failure
 */
-static struct ast_variable *realtime_odbc(const char *database, const char *table, va_list ap)
-{
-	struct odbc_obj *obj;
-	SQLHSTMT stmt;
-	char sql[1024];
-	char coltitle[256];
-	char rowdata[2048];
-	char *op;
+static struct ast_variable *realtime_curl(const char *url, const char *unused, va_list ap)
+{
+	struct ast_str *query;
+	char buf1[200], buf2[200];
 	const char *newparam, *newval;
-	char *stringp;
-	char *chunk;
-	SQLSMALLINT collen;
-	int res;
-	int x;
+	char *stringp, *pair, *key;
+	int i;
 	struct ast_variable *var=NULL, *prev=NULL;
-	SQLULEN colsize;
-	SQLSMALLINT colcount=0;
-	SQLSMALLINT datatype;
-	SQLSMALLINT decimaldigits;
-	SQLSMALLINT nullable;
-	SQLLEN indicator;
-	va_list aq;
-	struct custom_prepare_struct cps = { .sql = sql };
-
-	va_copy(cps.ap, ap);
-	va_copy(aq, ap);
-
-	if (!table)
-		return NULL;
-
-	obj = ast_odbc_request_obj(database, 0);
-
-	if (!obj) {
-		ast_log(LOG_ERROR, "No database handle available with the name of '%s' (check res_odbc.conf)\n", database);
-		return NULL;
-	}
-
-	newparam = va_arg(aq, const char *);
-	if (!newparam)
-		return NULL;
-	newval = 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 '\\'" : "");
-		newval = va_arg(aq, const char *);
-	}
-	va_end(aq);
-
-	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
-
-	if (!stmt) {
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-
-	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);
-		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-
-	res = SQLFetch(stmt);
-	if (res == SQL_NO_DATA) {
-		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
-		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-	for (x = 0; x < colcount; x++) {
-		rowdata[0] = '\0';
-		collen = sizeof(coltitle);
-		res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
-					&datatype, &colsize, &decimaldigits, &nullable);
-		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-			ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
-			if (var)
-				ast_variables_destroy(var);
-			ast_odbc_release_obj(obj);
-			return NULL;
+	const int EncodeSpecialChars = 1;
+	char *buffer;
+
+	if (!ast_custom_function_find("CURL")) {
+		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
+		return NULL;
+	}
+
+	if (!(query = ast_str_create(1000)))
+		return NULL;
+
+	if (!(buffer = ast_malloc(64000))) {
+		ast_free(query);
+		return NULL;
+	}
+
+	ast_str_set(&query, 0, "${CURL(%s,", url);
+
+	for (i = 0; (newparam = va_arg(ap, const char *)); i++) {
+		newval = va_arg(ap, const char *);
+		ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
+		ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+	}
+	va_end(ap);
+
+	ast_str_append(&query, 0, ")}");
+	pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
+
+	/* Remove any trailing newline characters */
+	if ((stringp = strchr(buffer, '\r')) || (stringp = strchr(buffer, '\n')))
+		*stringp = '\0';
+
+	stringp = buffer;
+	while ((pair = strsep(&stringp, "&"))) {
+		key = strsep(&pair, "=");
+		ast_uri_decode(key);
+		if (pair)
+			ast_uri_decode(pair);
+
+		if (!ast_strlen_zero(key)) {
+			if (prev) {
+				prev->next = ast_variable_new(key, S_OR(pair, ""), "");
+				if (prev->next)
+					prev = prev->next;
+			} else 
+				prev = var = ast_variable_new(key, S_OR(pair, ""), "");
 		}
-
-		indicator = 0;
-		res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
-		if (indicator == SQL_NULL_DATA)
-			rowdata[0] = '\0';
-		else if (ast_strlen_zero(rowdata)) {
-			/* Because we encode the empty string for a NULL, we will encode
-			 * actual empty strings as a string containing a single whitespace. */
-			ast_copy_string(rowdata, " ", sizeof(rowdata));
-		}
-
-		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-			ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
-			if (var)
-				ast_variables_destroy(var);
-			ast_odbc_release_obj(obj);
-			return NULL;
-		}
-		stringp = rowdata;
-		while(stringp) {
-			chunk = strsep(&stringp, ";");
-			if (!ast_strlen_zero(ast_strip(chunk))) {
-				if (prev) {
-					prev->next = ast_variable_new(coltitle, chunk, "");
-					if (prev->next)
-						prev = prev->next;
-				} else 
-					prev = var = ast_variable_new(coltitle, chunk, "");
-			}
-		}
-	}
-
-
-	SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-	ast_odbc_release_obj(obj);
+	}
+
+	ast_free(buffer);
+	ast_free(query);
 	return var;
 }
 
 /*!
  * \brief Excute an Select query and return ast_config list
- * \param database
- * \param table
+ * \param url
+ * \param unused
  * \param ap list containing one or more field/operator/value set.
  *
- * Select database and preform query on table, prepare the sql statement
- * Sub-in the values to the prepared statement and execute it. 
- * Execute this prepared query against several ODBC connected databases.
- * Return results as an ast_config variable.
- *
- * \retval var on success
+ * \retval struct ast_config pointer on success
  * \retval NULL on failure
 */
-static struct ast_config *realtime_multi_odbc(const char *database, const char *table, va_list ap)
-{
-	struct odbc_obj *obj;
-	SQLHSTMT stmt;
-	char sql[1024];
-	char coltitle[256];
-	char rowdata[2048];
-	const char *initfield=NULL;
-	char *op;
+static struct ast_config *realtime_multi_curl(const char *url, const char *unused, va_list ap)
+{
+	struct ast_str *query;
+	char buf1[200], buf2[200];
 	const char *newparam, *newval;
-	char *stringp;
-	char *chunk;
-	SQLSMALLINT collen;
-	int res;
-	int x;
+	char *stringp, *line, *pair, *key, *initfield = NULL;
+	int i, EncodeSpecialChars = 1;
 	struct ast_variable *var=NULL;
 	struct ast_config *cfg=NULL;
 	struct ast_category *cat=NULL;
-	SQLULEN colsize;
-	SQLSMALLINT colcount=0;
-	SQLSMALLINT datatype;
-	SQLSMALLINT decimaldigits;
-	SQLSMALLINT nullable;
-	SQLLEN indicator;
-	struct custom_prepare_struct cps = { .sql = sql };
-	va_list aq;
-
-	va_copy(cps.ap, ap);
-	va_copy(aq, ap);
-
-	if (!table)
-		return NULL;
-
-	obj = ast_odbc_request_obj(database, 0);
-	if (!obj)
-		return NULL;
-
-	newparam = va_arg(aq, const char *);
-	if (!newparam)  {
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-	initfield = ast_strdupa(newparam);
-	if ((op = strchr(initfield, ' '))) 
-		*op = '\0';
-	newval = 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 '\\'" : "");
-		newval = va_arg(aq, const char *);
-	}
-	if (initfield)
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " ORDER BY %s", initfield);
-	va_end(aq);
-
-	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
-
-	if (!stmt) {
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-
-	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);
-		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-
-	cfg = ast_config_new();
-	if (!cfg) {
-		ast_log(LOG_WARNING, "Out of memory!\n");
-		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-
-	while ((res=SQLFetch(stmt)) != SQL_NO_DATA) {
-		var = NULL;
-		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-			ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
+	char *buffer;
+
+	if (!ast_custom_function_find("CURL")) {
+		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
+		return NULL;
+	}
+
+	if (!(query = ast_str_create(1000)))
+		return NULL;
+
+	if (!(buffer = ast_malloc(256000))) {
+		ast_free(query);
+		return NULL;
+	}
+
+	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)
+			initfield = ast_strdupa(newparam);
+		ast_uri_encode(newparam, buf1, sizeof(buf1), EncodeSpecialChars);
+		ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+	}
+	va_end(ap);
+
+	ast_str_append(&query, 0, ")}");
+
+	/* Do the CURL query */
+	pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
+
+	if (!(cfg = ast_config_new()))
+		goto exit_multi;
+
+	/* Line oriented output */
+	stringp = buffer;
+	while ((line = strsep(&stringp, "\r\n"))) {
+		if (ast_strlen_zero(line))
 			continue;
-		}
-		cat = ast_category_new("","",99999);
-		if (!cat) {
-			ast_log(LOG_WARNING, "Out of memory!\n");
+
+		if (!(cat = ast_category_new("", "", 99999)))
 			continue;
-		}
-		for (x=0;x<colcount;x++) {
-			rowdata[0] = '\0';
-			collen = sizeof(coltitle);
-			res = SQLDescribeCol(stmt, x + 1, (unsigned char *)coltitle, sizeof(coltitle), &collen, 
-						&datatype, &colsize, &decimaldigits, &nullable);
-			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-				ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
-				ast_category_destroy(cat);
-				continue;
-			}
-
-			indicator = 0;
-			res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), &indicator);
-			if (indicator == SQL_NULL_DATA)
-				continue;
-
-			if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-				ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
-				ast_category_destroy(cat);
-				continue;
-			}
-			stringp = rowdata;
-			while(stringp) {
-				chunk = strsep(&stringp, ";");
-				if (!ast_strlen_zero(ast_strip(chunk))) {
-					if (initfield && !strcmp(initfield, coltitle))
-						ast_category_rename(cat, chunk);
-					var = ast_variable_new(coltitle, chunk, "");
-					ast_variable_append(cat, var);
-				}
+
+		while ((pair = strsep(&line, "&"))) {
+			key = strsep(&pair, "=");
+			ast_uri_decode(key);
+			if (pair)
+				ast_uri_decode(pair);
+
+			if (!strcasecmp(key, initfield) && pair)
+				ast_category_rename(cat, pair);
+
+			if (!ast_strlen_zero(key)) {
+				var = ast_variable_new(key, S_OR(pair, ""), "");
+				ast_variable_append(cat, var);
 			}
 		}
 		ast_category_append(cfg, cat);
 	}
 
-	SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-	ast_odbc_release_obj(obj);
+exit_multi:
+	ast_free(buffer);
+	ast_free(query);
 	return cfg;
 }
 
 /*!
- * \brief Excute an UPDATE query
- * \param database
- * \param table
+ * \brief Execute an UPDATE query
+ * \param url
+ * \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).
@@ -391,56 +217,52 @@
  * \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)
-{
-	struct odbc_obj *obj;
-	SQLHSTMT stmt;
-	char sql[256];
-	SQLLEN rowcount=0;
+static int update_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
+{
+	struct ast_str *query;
+	char buf1[200], buf2[200];
 	const char *newparam, *newval;
-	int res;
-	va_list aq;
-	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
-
-	va_copy(cps.ap, ap);
-	va_copy(aq, ap);
-	
-	if (!table)
-		return -1;
-
-	obj = ast_odbc_request_obj(database, 0);
-	if (!obj)
-		return -1;
-
-	newparam = va_arg(aq, const char *);
-	if (!newparam)  {
-		ast_odbc_release_obj(obj);
-		return -1;
-	}
-	newval = va_arg(aq, const char *);
-	snprintf(sql, sizeof(sql), "UPDATE %s SET %s=?", table, newparam);
-	while((newparam = va_arg(aq, const char *))) {
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), ", %s=?", newparam);
-		newval = va_arg(aq, const char *);
-	}
-	va_end(aq);
-	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), " WHERE %s=?", keyfield);
-
-	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
-
-	if (!stmt) {
-		ast_odbc_release_obj(obj);
-		return -1;
-	}
-
-	res = SQLRowCount(stmt, &rowcount);
-	SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-	ast_odbc_release_obj(obj);
-
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
-		return -1;
-	}
+	char *stringp;
+	int i, rowcount = -1;
+	const int EncodeSpecialChars = 1;
+	char *buffer;
+
+	if (!ast_custom_function_find("CURL")) {
+		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
+		return -1;
+	}
+
+	if (!(query = ast_str_create(1000)))
+		return -1;
+
+	if (!(buffer = ast_malloc(100))) {
+		ast_free(query);
+		return -1;
+	}
+
+	ast_uri_encode(keyfield, buf1, sizeof(buf1), EncodeSpecialChars);
+	ast_uri_encode(lookup, buf2, sizeof(buf2), EncodeSpecialChars);
+	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), EncodeSpecialChars);
+		ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+	}
+	va_end(ap);
+
+	ast_str_append(&query, 0, ")}");
+	pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
+
+	/* Line oriented output */
+	stringp = buffer;
+	while (*stringp <= ' ')
+		stringp++;
+	sscanf(stringp, "%d", &rowcount);
+
+	ast_free(buffer);
+	ast_free(query);
 
 	if (rowcount >= 0)
 		return (int)rowcount;
@@ -449,7 +271,7 @@
 }
 
 /*!
- * \brief Excute an INSERT query
+ * \brief Execute an INSERT query
  * \param database
  * \param table
  * \param ap list containing one or more field/value set(s)
@@ -461,60 +283,49 @@
  * \retval number of rows affected
  * \retval -1 on failure
 */
-static int store_odbc(const char *database, const char *table, va_list ap)
-{
-	struct odbc_obj *obj;
-	SQLHSTMT stmt;
-	char sql[256];
-	char keys[256];
-	char vals[256];
-	SQLLEN rowcount=0;
+static int store_curl(const char *url, const char *unused, va_list ap)
+{
+	struct ast_str *query;
+	char buf1[200], buf2[200];
 	const char *newparam, *newval;
-	int res;
-	va_list aq;
-	struct custom_prepare_struct cps = { .sql = sql, .extra = NULL };
-
-	va_copy(cps.ap, ap);
-	va_copy(aq, ap);
-	
-	if (!table)
-		return -1;
-
-	obj = ast_odbc_request_obj(database, 0);
-	if (!obj)
-		return -1;
-
-	newparam = va_arg(aq, const char *);
-	if (!newparam)  {
-		ast_odbc_release_obj(obj);
-		return -1;
-	}
-	newval = va_arg(aq, const char *);
-	snprintf(keys, sizeof(keys), "%s", newparam);
-	ast_copy_string(vals, "?", sizeof(vals));
-	while ((newparam = va_arg(aq, const char *))) {
-		snprintf(keys + strlen(keys), sizeof(keys) - strlen(keys), ", %s", newparam);
-		snprintf(vals + strlen(vals), sizeof(vals) - strlen(vals), ", ?");
-		newval = va_arg(aq, const char *);
-	}
-	va_end(aq);
-	snprintf(sql, sizeof(sql), "INSERT INTO %s (%s) VALUES (%s)", table, keys, vals);
-
-	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
-
-	if (!stmt) {
-		ast_odbc_release_obj(obj);
-		return -1;
-	}
-
-	res = SQLRowCount(stmt, &rowcount);
-	SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-	ast_odbc_release_obj(obj);
-
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
-		return -1;
-	}
+	char *stringp;
+	int i, rowcount = -1;
+	const int EncodeSpecialChars = 1;
+	char *buffer;
+
+	if (!ast_custom_function_find("CURL")) {
+		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
+		return -1;
+	}
+
+	if (!(query = ast_str_create(1000)))
+		return -1;
+
+	if (!(buffer = ast_malloc(100))) {
+		ast_free(query);
+		return -1;
+	}
+
+	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), EncodeSpecialChars);
+		ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+	}
+	va_end(ap);
+
+	ast_str_append(&query, 0, ")}");
+	pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
+
+	stringp = buffer;
+	while (*stringp <= ' ')
+		stringp++;
+	sscanf(stringp, "%d", &rowcount);
+
+	ast_free(buffer);
+	ast_free(query);
 
 	if (rowcount >= 0)
 		return (int)rowcount;
@@ -523,9 +334,9 @@
 }
 
 /*!
- * \brief Excute an DELETE query
- * \param database
- * \param table
+ * \brief Execute an DELETE query
+ * \param url
+ * \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)
@@ -537,50 +348,52 @@
  * \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)
-{
-	struct odbc_obj *obj;
-	SQLHSTMT stmt;
-	char sql[256];
-	SQLLEN rowcount=0;
+static int destroy_curl(const char *url, const char *unused, const char *keyfield, const char *lookup, va_list ap)
+{
+	struct ast_str *query;
+	char buf1[200], buf2[200];
 	const char *newparam, *newval;
-	int res;
-	va_list aq;
-	struct custom_prepare_struct cps = { .sql = sql, .extra = lookup };
-
-	va_copy(cps.ap, ap);
-	va_copy(aq, ap);
-	
-	if (!table)
-		return -1;
-
-	obj = ast_odbc_request_obj(database, 0);
-	if (!obj)
-		return -1;
-
-	snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE ", table);
-	while((newparam = va_arg(aq, const char *))) {
-		snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=? AND ", newparam);
-		newval = va_arg(aq, const char *);
-	}
-	va_end(aq);
-	snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql), "%s=?", keyfield);
-
-	stmt = ast_odbc_prepare_and_execute(obj, custom_prepare, &cps);
-
-	if (!stmt) {
-		ast_odbc_release_obj(obj);
-		return -1;
-	}
-
-	res = SQLRowCount(stmt, &rowcount);
-	SQLFreeHandle (SQL_HANDLE_STMT, stmt);
-	ast_odbc_release_obj(obj);
-
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
-		return -1;
-	}
+	char *stringp;
+	int i, rowcount = -1;
+	const int EncodeSpecialChars = 1;
+	char *buffer;
+
+	if (!ast_custom_function_find("CURL")) {
+		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
+		return -1;
+	}
+
+	if (!(query = ast_str_create(1000)))
+		return -1;
+
+	if (!(buffer = ast_malloc(100))) {
+		ast_free(query);
+		return -1;
+	}
+
+	ast_uri_encode(keyfield, buf1, sizeof(buf1), EncodeSpecialChars);
+	ast_uri_encode(lookup, buf2, sizeof(buf2), EncodeSpecialChars);
+	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), EncodeSpecialChars);
+		ast_uri_encode(newval, buf2, sizeof(buf2), EncodeSpecialChars);
+		ast_str_append(&query, 0, "%s%s=%s", i > 0 ? "&" : "", buf1, buf2);
+	}
+	va_end(ap);
+
+	ast_str_append(&query, 0, ")}");
+	pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
+
+	/* Line oriented output */
+	stringp = buffer;
+	while (*stringp <= ' ')
+		stringp++;
+	sscanf(stringp, "%d", &rowcount);
+
+	ast_free(buffer);
+	ast_free(query);
 
 	if (rowcount >= 0)
 		return (int)rowcount;
@@ -589,151 +402,102 @@
 }
 
 
-struct config_odbc_obj {
-	char *sql;
-	unsigned long cat_metric;
-	char category[128];
-	char var_name[128];
-	char var_val[1024]; /* changed from 128 to 1024 via bug 8251 */
-	SQLLEN err;
+static struct ast_config *config_curl(const char *url, const char *unused, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl)
+{
+	struct ast_str *query;
+	char buf1[200];
+	char *stringp, *line, *pair, *key;
+	int EncodeSpecialChars = 1, last_cat_metric = -1, cat_metric;
+	struct ast_category *cat=NULL;
+	char *buffer, *cur_cat = "";
+	char *category = "", *var_name = "", *var_val = "";
+	struct ast_flags loader_flags = { 0 };
+
+	if (!ast_custom_function_find("CURL")) {
+		ast_log(LOG_ERROR, "func_curl.so must be loaded in order to use res_config_curl.so!!\n");
+		return NULL;
+	}
+
+	if (!(query = ast_str_create(1000)))
+		return NULL;
+
+	if (!(buffer = ast_malloc(256000))) {
+		ast_free(query);
+		return NULL;
+	}
+
+	ast_uri_encode(file, buf1, sizeof(buf1), EncodeSpecialChars);
+	ast_str_set(&query, 0, "${CURL(%s/static?file=%s)}", url, buf1);
+
+	/* Do the CURL query */
+	pbx_substitute_variables_helper(NULL, query->str, buffer, sizeof(buffer));
+
+	/* Line oriented output */
+	stringp = buffer;
+	cat = ast_config_get_current_category(cfg);
+
+	while ((line = strsep(&stringp, "\r\n"))) {
+		if (ast_strlen_zero(line))
+			continue;
+
+		while ((pair = strsep(&line, "&"))) {
+			key = strsep(&pair, "=");
+			ast_uri_decode(key);
+			if (pair)
+				ast_uri_decode(pair);
+
+			if (!strcasecmp(key, "category"))
+				category = S_OR(pair, "");
+			else if (!strcasecmp(key, "var_name"))
+				var_name = S_OR(pair, "");
+			else if (!strcasecmp(key, "var_val"))
+				var_val = S_OR(pair, "");
+			else if (!strcasecmp(key, "cat_metric"))
+				cat_metric = pair ? atoi(pair) : 0;
+		}
+
+		if (!strcmp(var_name, "#include")) {
+			if (!ast_config_internal_load(var_val, cfg, loader_flags, ""))
+				return NULL;
+		}
+
+		if (strcmp(category, cur_cat) || last_cat_metric != cat_metric) {
+			if (!(cat = ast_category_new(category, "", 99999)))
+				break;
+			cur_cat = category;
+			last_cat_metric = cat_metric;
+			ast_category_append(cfg, cat);
+		}
+		ast_variable_append(cat, ast_variable_new(var_name, var_val, ""));
+	}
+
+	ast_free(buffer);
+	ast_free(query);
+	return cfg;
+}
+
+static struct ast_config_engine curl_engine = {
+	.name = "curl",
+	.load_func = config_curl,
+	.realtime_func = realtime_curl,
+	.realtime_multi_func = realtime_multi_curl,
+	.store_func = store_curl,
+	.destroy_func = destroy_curl,
+	.update_func = update_curl
 };
 
-static SQLHSTMT config_odbc_prepare(struct odbc_obj *obj, void *data)
-{
-	struct config_odbc_obj *q = data;
-	SQLHSTMT sth;
-	int res;
-
-	res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &sth);
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_verb(4, "Failure in AllocStatement %d\n", res);
-		return NULL;
-	}
-
-	res = SQLPrepare(sth, (unsigned char *)q->sql, SQL_NTS);
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_verb(4, "Error in PREPARE %d\n", res);
-		SQLFreeHandle(SQL_HANDLE_STMT, sth);
-		return NULL;
-	}
-
-	SQLBindCol(sth, 1, SQL_C_ULONG, &q->cat_metric, sizeof(q->cat_metric), &q->err);
-	SQLBindCol(sth, 2, SQL_C_CHAR, q->category, sizeof(q->category), &q->err);
-	SQLBindCol(sth, 3, SQL_C_CHAR, q->var_name, sizeof(q->var_name), &q->err);
-	SQLBindCol(sth, 4, SQL_C_CHAR, q->var_val, sizeof(q->var_val), &q->err);
-
-	return sth;
-}
-
-static struct ast_config *config_odbc(const char *database, const char *table, const char *file, struct ast_config *cfg, struct ast_flags flags, const char *sugg_incl)
-{
-	struct ast_variable *new_v;
-	struct ast_category *cur_cat;
-	int res = 0;
-	struct odbc_obj *obj;
-	char sqlbuf[1024] = "";
-	char *sql = sqlbuf;
-	size_t sqlleft = sizeof(sqlbuf);
-	unsigned int last_cat_metric = 0;
-	SQLSMALLINT rowcount = 0;
-	SQLHSTMT stmt;
-	char last[128] = "";
-	struct config_odbc_obj q;
-	struct ast_flags loader_flags = { 0 };
-
-	memset(&q, 0, sizeof(q));
-
-	if (!file || !strcmp (file, "res_config_odbc.conf"))
-		return NULL;		/* cant configure myself with myself ! */
-
-	obj = ast_odbc_request_obj(database, 0);
-	if (!obj)
-		return NULL;
-
-	ast_build_string(&sql, &sqlleft, "SELECT cat_metric, category, var_name, var_val FROM %s ", table);
-	ast_build_string(&sql, &sqlleft, "WHERE filename='%s' AND commented=0 ", file);
-	ast_build_string(&sql, &sqlleft, "ORDER BY cat_metric DESC, var_metric ASC, category, var_name ");
-	q.sql = sqlbuf;
-
-	stmt = ast_odbc_prepare_and_execute(obj, config_odbc_prepare, &q);
-
-	if (!stmt) {
-		ast_log(LOG_WARNING, "SQL select error!\n[%s]\n\n", sql);
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-
-	res = SQLNumResultCols(stmt, &rowcount);
-
-	if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
-		ast_log(LOG_WARNING, "SQL NumResultCols error!\n[%s]\n\n", sql);
-		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-		ast_odbc_release_obj(obj);
-		return NULL;
-	}
-
-	if (!rowcount) {
-		ast_log(LOG_NOTICE, "found nothing\n");
-		ast_odbc_release_obj(obj);
-		return cfg;
-	}
-
-	cur_cat = ast_config_get_current_category(cfg);
-
-	while ((res = SQLFetch(stmt)) != SQL_NO_DATA) {
-		if (!strcmp (q.var_name, "#include")) {
-			if (!ast_config_internal_load(q.var_val, cfg, loader_flags, "")) {
-				SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-				ast_odbc_release_obj(obj);
-				return NULL;
-			}
-			continue;
-		} 
-		if (strcmp(last, q.category) || last_cat_metric != q.cat_metric) {
-			cur_cat = ast_category_new(q.category, "", 99999);
-			if (!cur_cat) {
-				ast_log(LOG_WARNING, "Out of memory!\n");
-				break;
-			}
-			strcpy(last, q.category);
-			last_cat_metric	= q.cat_metric;
-			ast_category_append(cfg, cur_cat);
-		}
-
-		new_v = ast_variable_new(q.var_name, q.var_val, "");
-		ast_variable_append(cur_cat, new_v);
-	}
-
-	SQLFreeHandle(SQL_HANDLE_STMT, stmt);
-	ast_odbc_release_obj(obj);
-	return cfg;
-}
-
-static struct ast_config_engine odbc_engine = {
-	.name = "odbc",
-	.load_func = config_odbc,
-	.realtime_func = realtime_odbc,
-	.realtime_multi_func = realtime_multi_odbc,
-	.store_func = store_odbc,
-	.destroy_func = destroy_odbc,
-	.update_func = update_odbc
-};
-
 static int unload_module (void)
 {
-	ast_config_engine_deregister(&odbc_engine);
-	ast_verb(1, "res_config_odbc unloaded.\n");
+	ast_config_engine_deregister(&curl_engine);
+	ast_verb(1, "res_config_curl unloaded.\n");
 	return 0;
 }
 
 static int load_module (void)
 {
-	ast_config_engine_register(&odbc_engine);
-	ast_verb(1, "res_config_odbc loaded.\n");
+	ast_config_engine_register(&curl_engine);
+	ast_verb(1, "res_config_curl loaded.\n");
 	return 0;
 }
 
-AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Realtime ODBC configuration",
-		.load = load_module,
-		.unload = unload_module,
-		);
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Realtime Curl configuration");




More information about the asterisk-commits mailing list