[asterisk-commits] murf: branch group/newcdr r166903 - in /team/group/newcdr: cel/ configs/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Dec 30 14:21:27 CST 2008


Author: murf
Date: Tue Dec 30 14:21:26 2008
New Revision: 166903

URL: http://svn.digium.com/view/asterisk?view=rev&rev=166903
Log:
OK, I brought in and converted the adaptive_odbc
stuff to cel.
I updated the pgsql back end be more adaptive-odbc-like,
as the current version is.
I removed the cel_odbc entirely. the adaptive odbc
stuff provides the functionality, why support two?
I updated the adaptive_odbc and pgsql conf samples
to include the cel field names


Added:
    team/group/newcdr/cel/cel_adaptive_odbc.c   (with props)
    team/group/newcdr/configs/cel_adaptive_odbc.conf.sample   (with props)
Removed:
    team/group/newcdr/cel/cel_odbc.c
Modified:
    team/group/newcdr/cel/cel_pgsql.c
    team/group/newcdr/configs/cel_pgsql.conf.sample

Added: team/group/newcdr/cel/cel_adaptive_odbc.c
URL: http://svn.digium.com/view/asterisk/team/group/newcdr/cel/cel_adaptive_odbc.c?view=auto&rev=166903
==============================================================================
--- team/group/newcdr/cel/cel_adaptive_odbc.c (added)
+++ team/group/newcdr/cel/cel_adaptive_odbc.c Tue Dec 30 14:21:26 2008
@@ -1,0 +1,797 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2008 Digium
+ *
+ * Adapted from cdr_adaptive_odbc:
+ * Tilghman Lesher <cdr_adaptive_odbc__v1 at the-tilghman.com>
+ * by Steve Murphy
+ *
+ * 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 Adaptive ODBC CEL backend
+ *
+ * \author Tilghman Lesher <cdr_adaptive_odbc__v1 at the-tilghman.com>
+ * \ingroup cel_drivers
+ */
+
+/*** MODULEINFO
+	<depend>odbc</depend>
+	<use>unixodbc</use>
+	<use>iodbc</use>
+ ***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include <sys/types.h>
+#include <time.h>
+
+#include <sql.h>
+#include <sqlext.h>
+#include <sqltypes.h>
+
+#include "asterisk/config.h"
+#include "asterisk/channel.h"
+#include "asterisk/lock.h"
+#include "asterisk/linkedlists.h"
+#include "asterisk/res_odbc.h"
+#include "asterisk/cel.h"
+#include "asterisk/module.h"
+
+#define	CONFIG	"cel_adaptive_odbc.conf"
+static struct ast_event_sub *event_sub = 0;
+
+/* Optimization to reduce number of memory allocations */
+static int maxsize = 512, maxsize2 = 512;
+
+struct columns {
+	char *name;
+	char *celname;
+	char *filtervalue;
+	char *staticvalue;
+	SQLSMALLINT type;
+	SQLINTEGER size;
+	SQLSMALLINT decimals;
+	SQLSMALLINT radix;
+	SQLSMALLINT nullable;
+	SQLINTEGER octetlen;
+	AST_LIST_ENTRY(columns) list;
+};
+
+struct tables {
+	char *connection;
+	char *table;
+	unsigned int usegmtime:1;
+	AST_LIST_HEAD_NOLOCK(odbc_columns, columns) columns;
+	AST_RWLIST_ENTRY(tables) list;
+};
+
+static AST_RWLIST_HEAD_STATIC(odbc_tables, tables);
+
+static int load_config(void)
+{
+	struct ast_config *cfg;
+	struct ast_variable *var;
+	const char *tmp, *catg;
+	struct tables *tableptr;
+	struct columns *entry;
+	struct odbc_obj *obj;
+	char columnname[80];
+	char connection[40];
+	char table[40];
+	int lenconnection, lentable, usegmtime = 0;
+	SQLLEN sqlptr;
+	int res = 0;
+	SQLHSTMT stmt = NULL;
+	struct ast_flags config_flags = { 0 }; /* Part of our config comes from the database */
+
+	cfg = ast_config_load(CONFIG, config_flags);
+	if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
+		ast_log(LOG_WARNING, "Unable to load " CONFIG ".  No adaptive ODBC CEL records!\n");
+		return -1;
+	}
+
+	for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
+		var = ast_variable_browse(cfg, catg);
+		if (!var)
+			continue;
+
+		if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "connection"))) {
+			ast_log(LOG_WARNING, "No connection parameter found in '%s'.  Skipping.\n", catg);
+			continue;
+		}
+		ast_copy_string(connection, tmp, sizeof(connection));
+		lenconnection = strlen(connection);
+
+		if (!ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "usegmtime"))) {
+			usegmtime = ast_true(tmp);
+		}
+
+		/* When loading, we want to be sure we can connect. */
+		obj = ast_odbc_request_obj(connection, 1);
+		if (!obj) {
+			ast_log(LOG_WARNING, "No such connection '%s' in the '%s' section of " CONFIG ".  Check res_odbc.conf.\n", connection, catg);
+			continue;
+		}
+
+		if (ast_strlen_zero(tmp = ast_variable_retrieve(cfg, catg, "table"))) {
+			ast_log(LOG_NOTICE, "No table name found.  Assuming 'cel'.\n");
+			tmp = "cel";
+		}
+		ast_copy_string(table, tmp, sizeof(table));
+		lentable = strlen(table);
+
+		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 on connection '%s'!\n", connection);
+			ast_odbc_release_obj(obj);
+			continue;
+		}
+
+		res = SQLColumns(stmt, NULL, 0, NULL, 0, (unsigned char *)table, SQL_NTS, (unsigned char *)"%", SQL_NTS);
+		if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
+			ast_log(LOG_ERROR, "Unable to query database columns on connection '%s'.  Skipping.\n", connection);
+			ast_odbc_release_obj(obj);
+			continue;
+		}
+
+		tableptr = ast_calloc(sizeof(char), sizeof(*tableptr) + lenconnection + 1 + lentable + 1);
+		if (!tableptr) {
+			ast_log(LOG_ERROR, "Out of memory creating entry for table '%s' on connection '%s'\n", table, connection);
+			ast_odbc_release_obj(obj);
+			res = -1;
+			break;
+		}
+
+		tableptr->usegmtime = usegmtime;
+		tableptr->connection = (char *)tableptr + sizeof(*tableptr);
+		tableptr->table = (char *)tableptr + sizeof(*tableptr) + lenconnection + 1;
+		ast_copy_string(tableptr->connection, connection, lenconnection + 1);
+		ast_copy_string(tableptr->table, table, lentable + 1);
+
+		ast_verb(3, "Found adaptive CEL table %s@%s.\n", tableptr->table, tableptr->connection);
+
+		/* Check for filters first */
+		for (var = ast_variable_browse(cfg, catg); var; var = var->next) {
+			if (strncmp(var->name, "filter", 6) == 0) {
+				char *celvar = ast_strdupa(var->name + 6);
+				celvar = ast_strip(celvar);
+				ast_verb(3, "Found filter %s for cel variable %s in %s@%s\n", var->value, celvar, tableptr->table, tableptr->connection);
+
+				entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(celvar) + 1 + strlen(var->value) + 1);
+				if (!entry) {
+					ast_log(LOG_ERROR, "Out of memory creating filter entry for CEL variable '%s' in table '%s' on connection '%s'\n", celvar, table, connection);
+					res = -1;
+					break;
+				}
+
+				/* NULL column entry means this isn't a column in the database */
+				entry->name = NULL;
+				entry->celname = (char *)entry + sizeof(*entry);
+				entry->filtervalue = (char *)entry + sizeof(*entry) + strlen(celvar) + 1;
+				strcpy(entry->celname, celvar);
+				strcpy(entry->filtervalue, var->value);
+
+				AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
+			}
+		}
+
+		while ((res = SQLFetch(stmt)) != SQL_NO_DATA && res != SQL_ERROR) {
+			char *celvar = "", *staticvalue = "";
+
+			SQLGetData(stmt,  4, SQL_C_CHAR, columnname, sizeof(columnname), &sqlptr);
+
+			/* Is there an alias for this column? */
+
+			/* NOTE: This seems like a non-optimal parse method, but I'm going
+			 * for user configuration readability, rather than fast parsing. We
+			 * really don't parse this file all that often, anyway.
+			 */
+			for (var = ast_variable_browse(cfg, catg); var; var = var->next) {
+				if (strncmp(var->name, "alias", 5) == 0 && strcasecmp(var->value, columnname) == 0) {
+					char *alias = ast_strdupa(var->name + 5);
+					celvar = ast_strip(alias);
+					ast_verb(3, "Found alias %s for column %s in %s@%s\n", celvar, columnname, tableptr->table, tableptr->connection);
+					break;
+				} else if (strncmp(var->name, "static", 6) == 0 && strcasecmp(var->value, columnname) == 0) {
+					char *item = ast_strdupa(var->name + 6);
+					item = ast_strip(item);
+					if (item[0] == '"' && item[strlen(item) - 1] == '"') {
+						/* Remove surrounding quotes */
+						item[strlen(item) - 1] = '\0';
+						item++;
+					}
+					staticvalue = item;
+				}
+			}
+
+			entry = ast_calloc(sizeof(char), sizeof(*entry) + strlen(columnname) + 1 + strlen(celvar) + 1 + strlen(staticvalue) + 1);
+			if (!entry) {
+				ast_log(LOG_ERROR, "Out of memory creating entry for column '%s' in table '%s' on connection '%s'\n", columnname, table, connection);
+				res = -1;
+				break;
+			}
+			entry->name = (char *)entry + sizeof(*entry);
+			strcpy(entry->name, columnname);
+
+			if (!ast_strlen_zero(celvar)) {
+				entry->celname = entry->name + strlen(columnname) + 1;
+				strcpy(entry->celname, celvar);
+			} else { /* Point to same place as the column name */
+				entry->celname = (char *)entry + sizeof(*entry);
+			}
+
+			if (!ast_strlen_zero(staticvalue)) {
+				entry->staticvalue = entry->celname + strlen(entry->celname) + 1;
+				strcpy(entry->staticvalue, staticvalue);
+			}
+
+			SQLGetData(stmt,  5, SQL_C_SHORT, &entry->type, sizeof(entry->type), NULL);
+			SQLGetData(stmt,  7, SQL_C_LONG, &entry->size, sizeof(entry->size), NULL);
+			SQLGetData(stmt,  9, SQL_C_SHORT, &entry->decimals, sizeof(entry->decimals), NULL);
+			SQLGetData(stmt, 10, SQL_C_SHORT, &entry->radix, sizeof(entry->radix), NULL);
+			SQLGetData(stmt, 11, SQL_C_SHORT, &entry->nullable, sizeof(entry->nullable), NULL);
+			SQLGetData(stmt, 16, SQL_C_LONG, &entry->octetlen, sizeof(entry->octetlen), NULL);
+
+			/* Specification states that the octenlen should be the maximum number of bytes
+			 * returned in a char or binary column, but it seems that some drivers just set
+			 * it to NULL. (Bad Postgres! No biscuit!) */
+			if (entry->octetlen == 0)
+				entry->octetlen = entry->size;
+
+			ast_verb(10, "Found %s column with type %hd with len %ld, octetlen %ld, and numlen (%hd,%hd)\n", entry->name, entry->type, (long) entry->size, (long) entry->octetlen, entry->decimals, entry->radix);
+			/* Insert column info into column list */
+			AST_LIST_INSERT_TAIL(&(tableptr->columns), entry, list);
+			res = 0;
+		}
+
+		SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+		ast_odbc_release_obj(obj);
+
+		if (AST_LIST_FIRST(&(tableptr->columns)))
+			AST_RWLIST_INSERT_TAIL(&odbc_tables, tableptr, list);
+		else
+			ast_free(tableptr);
+	}
+	return res;
+}
+
+static int free_config(void)
+{
+	struct tables *table;
+	struct columns *entry;
+	while ((table = AST_RWLIST_REMOVE_HEAD(&odbc_tables, list))) {
+		while ((entry = AST_LIST_REMOVE_HEAD(&(table->columns), list))) {
+			ast_free(entry);
+		}
+		ast_free(table);
+	}
+	return 0;
+}
+
+static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
+{
+	int res, i;
+	char *sql = data;
+	SQLHSTMT stmt;
+	SQLINTEGER nativeerror = 0, numfields = 0;
+	SQLSMALLINT diagbytes = 0;
+	unsigned char state[10], diagnostic[256];
+
+	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);
+		SQLGetDiagField(SQL_HANDLE_STMT, stmt, 1, SQL_DIAG_NUMBER, &numfields, SQL_IS_INTEGER, &diagbytes);
+		for (i = 0; i < numfields; i++) {
+			SQLGetDiagRec(SQL_HANDLE_STMT, stmt, i + 1, state, &nativeerror, diagnostic, sizeof(diagnostic), &diagbytes);
+			ast_log(LOG_WARNING, "SQL Execute returned an error %d: %s: %s (%d)\n", res, state, diagnostic, diagbytes);
+			if (i > 10) {
+				ast_log(LOG_WARNING, "Oh, that was good.  There are really %d diagnostics?\n", (int)numfields);
+				break;
+			}
+		}
+		SQLFreeHandle (SQL_HANDLE_STMT, stmt);
+		return NULL;
+	}
+
+	return stmt;
+}
+
+#define LENGTHEN_BUF1(size)														\
+			do {																\
+				/* Lengthen buffer, if necessary */								\
+				if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) {       \
+					if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 1) / 512 + 1) * 512) != 0) { \
+						ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CEL '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
+						ast_free(sql);											\
+						ast_free(sql2);											\
+						AST_RWLIST_UNLOCK(&odbc_tables);						\
+						return;													\
+					}															\
+				}																\
+			} while (0)
+
+#define LENGTHEN_BUF2(size)														\
+			do {																\
+				if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) {     \
+					if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \
+						ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CEL '%s:%s' failed.\n", tableptr->connection, tableptr->table); \
+						ast_free(sql);											\
+						ast_free(sql2);											\
+						AST_RWLIST_UNLOCK(&odbc_tables);						\
+						return;													\
+					}															\
+				}																\
+			} while (0)
+
+static void odbc_log(const struct ast_event *event, void *userdata)
+{
+	struct tables *tableptr;
+	struct columns *entry;
+	struct odbc_obj *obj;
+	struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
+	char *tmp;
+	char colbuf[1024], *colptr;
+	SQLHSTMT stmt = NULL;
+	SQLLEN rows = 0;
+	enum ast_cel_eventtype eventtype;
+	const char *userdefname = 0;
+	struct timeval eventtime = {0};
+	const char *cid_ani, *cid_rdnis, *cid_name, *cid_num, *cid_dnid;
+	const char *exten, *context, *channame, *appname, *appdata, *accountcode, *peeraccount, *uniqueid, *linkedid, *userfield, *peer;
+	unsigned int amaflag;
+
+	if (!sql || !sql2) {
+		if (sql)
+			ast_free(sql);
+		if (sql2)
+			ast_free(sql2);
+		return;
+	}
+	eventtype = (enum ast_cel_eventtype)ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_EVENT_TYPE);
+	eventtime.tv_sec = (time_t)ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_EVENT_TIME);
+	eventtime.tv_usec = (time_t)ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
+	if (eventtype == CEL_USER_DEFINED) {
+		userdefname = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_USEREVENT_NAME);
+	}
+	cid_name = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CIDNAME);
+	cid_num = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CIDNUM);
+	cid_ani = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CIDANI);
+	cid_rdnis = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CIDRDNIS);
+	cid_dnid = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CIDDNID);
+	exten = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_EXTEN);
+	context = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CONTEXT);
+	channame = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_CHANNAME);
+	appname = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_APPNAME);
+	appdata = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_APPDATA);
+	accountcode = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_ACCTCODE);
+	peeraccount = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_ACCTCODE);
+	uniqueid = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_UNIQUEID);
+	linkedid = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_LINKEDID);
+	amaflag = ast_event_get_ie_uint(event, AST_EVENT_IE_CEL_AMAFLAGS);
+	userfield = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_USERFIELD);
+	peer = ast_event_get_ie_str(event, AST_EVENT_IE_CEL_PEER);
+
+	if (AST_RWLIST_RDLOCK(&odbc_tables)) {
+		ast_log(LOG_ERROR, "Unable to lock table list.  Insert CEL(s) failed.\n");
+		ast_free(sql);
+		ast_free(sql2);
+		return;
+	}
+
+	AST_LIST_TRAVERSE(&odbc_tables, tableptr, list) {
+		int first = 1;
+		ast_str_set(&sql, 0, "INSERT INTO %s (", tableptr->table);
+		ast_str_set(&sql2, 0, " VALUES (");
+
+		/* No need to check the connection now; we'll handle any failure in prepare_and_execute */
+		if (!(obj = ast_odbc_request_obj(tableptr->connection, 0))) {
+			ast_log(LOG_WARNING, "cel_adaptive_odbc: Unable to retrieve database handle for '%s:%s'.  CEL failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
+			continue;
+		}
+
+		AST_LIST_TRAVERSE(&(tableptr->columns), entry, list) {
+			int datefield = 0;
+			if (strcasecmp(entry->celname, "eventtime") == 0) {
+				datefield = 1;
+			}
+
+			/* Check if we have a similarly named variable */
+			if (entry->staticvalue) {
+				colptr = ast_strdupa(entry->staticvalue);
+			} else if (datefield) {
+				struct timeval date_tv = eventtime;
+				struct ast_tm tm = { 0, };
+				ast_localtime(&date_tv, &tm, tableptr->usegmtime ? "UTC" : NULL);
+				ast_strftime(colbuf, sizeof(colbuf), "%Y-%m-%d %H:%M:%S", &tm);
+				colptr = colbuf;
+			} else {
+				if (strcmp(entry->celname, "userdeftype") == 0) {
+					strncpy(colbuf, userdefname, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "cid_name") == 0) {
+					strncpy(colbuf, cid_name, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "cid_num") == 0) {
+					strncpy(colbuf, cid_num, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "cid_ani") == 0) {
+					strncpy(colbuf, cid_ani, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "cid_rdnis") == 0) {
+					strncpy(colbuf, cid_rdnis, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "cid_dnid") == 0) {
+					strncpy(colbuf, cid_dnid, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "exten") == 0) {
+					strncpy(colbuf, exten, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "context") == 0) {
+					strncpy(colbuf, context, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "channame") == 0) {
+					strncpy(colbuf, channame, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "appname") == 0) {
+					strncpy(colbuf, appname, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "appdata") == 0) {
+					strncpy(colbuf, appdata, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "accountcode") == 0) {
+					strncpy(colbuf, accountcode, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "peeraccount") == 0) {
+					strncpy(colbuf, peeraccount, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "uniqueid") == 0) {
+					strncpy(colbuf, uniqueid, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "linkedid") == 0) {
+					strncpy(colbuf, linkedid, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "userfield") == 0) {
+					strncpy(colbuf, userfield, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "peer") == 0) {
+					strncpy(colbuf, peer, sizeof(colbuf));
+				} else if (strcmp(entry->celname, "amaflags") == 0) {
+					snprintf(colbuf, sizeof(colbuf), "%d", amaflag);
+				} else {
+					colbuf[0] = 0;
+				}
+				colptr = colbuf;
+			}
+
+			if (colptr) {
+				/* Check first if the column filters this entry.  Note that this
+				 * is very specifically NOT ast_strlen_zero(), because the filter
+				 * could legitimately specify that the field is blank, which is
+				 * different from the field being unspecified (NULL). */
+				if (entry->filtervalue && strcasecmp(colptr, entry->filtervalue) != 0) {
+					ast_verb(4, "CEL column '%s' with value '%s' does not match filter of"
+						" '%s'.  Cancelling this CEL.\n",
+						entry->celname, colptr, entry->filtervalue);
+					goto early_release;
+				}
+
+				/* Only a filter? */
+				if (ast_strlen_zero(entry->name))
+					continue;
+
+				LENGTHEN_BUF1(strlen(entry->name));
+
+				switch (entry->type) {
+				case SQL_CHAR:
+				case SQL_VARCHAR:
+				case SQL_LONGVARCHAR:
+				case SQL_BINARY:
+				case SQL_VARBINARY:
+				case SQL_LONGVARBINARY:
+				case SQL_GUID:
+					/* For these two field names, get the rendered form, instead of the raw
+					 * form (but only when we're dealing with a character-based field).
+					 */
+					if (strcasecmp(entry->name, "eventtype") == 0) {
+						snprintf(colbuf, sizeof(colbuf), "%s", ast_cel_eventtype2str(eventtype));
+					}
+
+					/* Truncate too-long fields */
+					if (entry->type != SQL_GUID) {
+						if (strlen(colptr) > entry->octetlen) {
+							colptr[entry->octetlen] = '\0';
+						}
+					}
+
+					ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+					LENGTHEN_BUF2(strlen(colptr));
+
+					/* Encode value, with escaping */
+					ast_str_append(&sql2, 0, "%s'", first ? "" : ",");
+					for (tmp = colptr; *tmp; tmp++) {
+						if (*tmp == '\'') {
+							ast_str_append(&sql2, 0, "''");
+						} else if (*tmp == '\\' && ast_odbc_backslash_is_escape(obj)) {
+							ast_str_append(&sql2, 0, "\\\\");
+						} else {
+							ast_str_append(&sql2, 0, "%c", *tmp);
+						}
+					}
+					ast_str_append(&sql2, 0, "'");
+					break;
+				case SQL_TYPE_DATE:
+					{
+						int year = 0, month = 0, day = 0;
+						if (sscanf(colptr, "%d-%d-%d", &year, &month, &day) != 3 || year <= 0 ||
+							month <= 0 || month > 12 || day < 0 || day > 31 ||
+							((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
+							(month == 2 && year % 400 == 0 && day > 29) ||
+							(month == 2 && year % 100 == 0 && day > 28) ||
+							(month == 2 && year % 4 == 0 && day > 29) ||
+							(month == 2 && year % 4 != 0 && day > 28)) {
+							ast_log(LOG_WARNING, "CEL variable %s is not a valid date ('%s').\n", entry->name, colptr);
+							continue;
+						}
+
+						if (year > 0 && year < 100) {
+							year += 2000;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(17);
+						ast_str_append(&sql2, 0, "%s{ d '%04d-%02d-%02d' }", first ? "" : ",", year, month, day);
+					}
+					break;
+				case SQL_TYPE_TIME:
+					{
+						int hour = 0, minute = 0, second = 0;
+						int count = sscanf(colptr, "%d:%d:%d", &hour, &minute, &second);
+
+						if ((count != 2 && count != 3) || hour < 0 || hour > 23 || minute < 0 || minute > 59 || second < 0 || second > 59) {
+							ast_log(LOG_WARNING, "CEL variable %s is not a valid time ('%s').\n", entry->name, colptr);
+							continue;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(15);
+						ast_str_append(&sql2, 0, "%s{ t '%02d:%02d:%02d' }", first ? "" : ",", hour, minute, second);
+					}
+					break;
+				case SQL_TYPE_TIMESTAMP:
+				case SQL_TIMESTAMP:
+					{
+						int year = 0, month = 0, day = 0, hour = 0, minute = 0, second = 0;
+						int count = sscanf(colptr, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second);
+
+						if ((count != 3 && count != 5 && count != 6) || year <= 0 ||
+							month <= 0 || month > 12 || day < 0 || day > 31 ||
+							((month == 4 || month == 6 || month == 9 || month == 11) && day == 31) ||
+							(month == 2 && year % 400 == 0 && day > 29) ||
+							(month == 2 && year % 100 == 0 && day > 28) ||
+							(month == 2 && year % 4 == 0 && day > 29) ||
+							(month == 2 && year % 4 != 0 && day > 28) ||
+							hour > 23 || minute > 59 || second > 59 || hour < 0 || minute < 0 || second < 0) {
+							ast_log(LOG_WARNING, "CEL variable %s is not a valid timestamp ('%s').\n", entry->name, colptr);
+							continue;
+						}
+
+						if (year > 0 && year < 100) {
+							year += 2000;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(26);
+						ast_str_append(&sql2, 0, "%s{ ts '%04d-%02d-%02d %02d:%02d:%02d' }", first ? "" : ",", year, month, day, hour, minute, second);
+					}
+					break;
+				case SQL_INTEGER:
+					{
+						int integer = 0;
+						if (strcasecmp(entry->name, "eventtype") == 0) {
+							integer = (int)eventtype;
+						} else if (sscanf(colptr, "%d", &integer) != 1) {
+							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
+							continue;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(12);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+					}
+					break;
+				case SQL_BIGINT:
+					{
+						long long integer = 0;
+						if (strcasecmp(entry->name, "eventtype") == 0) {
+							integer = (long long)eventtype;
+						} else if (sscanf(colptr, "%lld", &integer) != 1) {
+							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
+							continue;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(24);
+						ast_str_append(&sql2, 0, "%s%lld", first ? "" : ",", integer);
+					}
+					break;
+				case SQL_SMALLINT:
+					{
+						short integer = 0;
+						if (strcasecmp(entry->name, "eventtype") == 0) {
+							integer = (short)eventtype;
+						} else if (sscanf(colptr, "%hd", &integer) != 1) {
+							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
+							continue;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(6);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+					}
+					break;
+				case SQL_TINYINT:
+					{
+						char integer = 0;
+						if (strcasecmp(entry->name, "eventtype") == 0) {
+							integer = (char)eventtype;
+						} else if (sscanf(colptr, "%hhd", &integer) != 1) {
+							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
+							continue;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(4);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+					}
+					break;
+				case SQL_BIT:
+					{
+						char integer = 0;
+						if (strcasecmp(entry->name, "eventtype") == 0) {
+							integer = (char)eventtype;
+						} else if (sscanf(colptr, "%hhd", &integer) != 1) {
+							ast_log(LOG_WARNING, "CEL variable %s is not an integer.\n", entry->name);
+							continue;
+						}
+						if (integer != 0)
+							integer = 1;
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(2);
+						ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", integer);
+					}
+					break;
+				case SQL_NUMERIC:
+				case SQL_DECIMAL:
+					{
+						double number = 0.0;
+						if (strcasecmp(entry->name, "eventtype") == 0) {
+							number = (double)eventtype;
+						} else if (sscanf(colptr, "%lf", &number) != 1) {
+							ast_log(LOG_WARNING, "CEL variable %s is not an numeric type.\n", entry->name);
+							continue;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(entry->decimals);
+						ast_str_append(&sql2, 0, "%s%*.*lf", first ? "" : ",", entry->decimals, entry->radix, number);
+					}
+					break;
+				case SQL_FLOAT:
+				case SQL_REAL:
+				case SQL_DOUBLE:
+					{
+						double number = 0.0;
+						if (strcasecmp(entry->name, "eventtype") == 0) {
+							number = (double)eventtype;
+						} else if (sscanf(colptr, "%lf", &number) != 1) {
+							ast_log(LOG_WARNING, "CEL variable %s is not an numeric type.\n", entry->name);
+							continue;
+						}
+
+						ast_str_append(&sql, 0, "%s%s", first ? "" : ",", entry->name);
+						LENGTHEN_BUF2(entry->decimals);
+						ast_str_append(&sql2, 0, "%s%lf", first ? "" : ",", number);
+					}
+					break;
+				default:
+					ast_log(LOG_WARNING, "Column type %d (field '%s:%s:%s') is unsupported at this time.\n", entry->type, tableptr->connection, tableptr->table, entry->name);
+					continue;
+				}
+				first = 0;
+			}
+		}
+
+		/* Concatenate the two constructed buffers */
+		LENGTHEN_BUF1(ast_str_strlen(sql2));
+		ast_str_append(&sql, 0, ")");
+		ast_str_append(&sql2, 0, ")");
+		ast_str_append(&sql, 0, "%s", ast_str_buffer(sql2));
+
+		ast_verb(11, "[%s]\n", ast_str_buffer(sql));
+
+		stmt = ast_odbc_prepare_and_execute(obj, generic_prepare, ast_str_buffer(sql));
+		if (stmt) {
+			SQLRowCount(stmt, &rows);
+			SQLFreeHandle(SQL_HANDLE_STMT, stmt);
+		}
+		if (rows == 0) {
+			ast_log(LOG_WARNING, "cel_adaptive_odbc: Insert failed on '%s:%s'.  CEL failed: %s\n", tableptr->connection, tableptr->table, ast_str_buffer(sql));
+		}
+early_release:
+		ast_odbc_release_obj(obj);
+	}
+	AST_RWLIST_UNLOCK(&odbc_tables);
+
+	/* Next time, just allocate buffers that are that big to start with. */
+	if (ast_str_strlen(sql) > maxsize) {
+		maxsize = ast_str_strlen(sql);
+	}
+	if (ast_str_strlen(sql2) > maxsize2) {
+		maxsize2 = ast_str_strlen(sql2);
+	}
+
+	ast_free(sql);
+	ast_free(sql2);
+	return;
+}
+
+static int unload_module(void)
+{
+	if (event_sub) {
+		ast_event_unsubscribe(event_sub);
+	}
+	event_sub = 0;
+	usleep(1);
+	if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+		event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "Adaptive ODBC CEL backend", NULL, AST_EVENT_IE_END);
+		if (!event_sub) {
+			ast_log(LOG_ERROR, "cel_adaptive_odbc: Unable to subscribe to CEL events\n");
+		}
+		ast_log(LOG_ERROR, "Unable to lock column list.  Unload failed.\n");
+		return -1;
+	}
+
+	free_config();
+	AST_RWLIST_UNLOCK(&odbc_tables);
+	return 0;
+}
+
+static int load_module(void)
+{
+	if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+		ast_log(LOG_ERROR, "Unable to lock column list.  Load failed.\n");
+		return 0;
+	}
+	load_config();
+	AST_RWLIST_UNLOCK(&odbc_tables);
+	event_sub = ast_event_subscribe(AST_EVENT_CEL, odbc_log, "Adaptive ODBC CEL backend", NULL, AST_EVENT_IE_END);
+	if (!event_sub) {
+		ast_log(LOG_ERROR, "cel_odbc: Unable to subscribe to CEL events\n");
+	}
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+static int reload(void)
+{
+	if (AST_RWLIST_WRLOCK(&odbc_tables)) {
+		ast_log(LOG_ERROR, "Unable to lock column list.  Reload failed.\n");
+		return -1;
+	}
+
+	free_config();
+	load_config();
+	AST_RWLIST_UNLOCK(&odbc_tables);
+	return AST_MODULE_LOAD_SUCCESS;
+}
+
+AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Adaptive ODBC CEL backend",
+	.load = load_module,
+	.unload = unload_module,
+	.reload = reload,
+);
+

Propchange: team/group/newcdr/cel/cel_adaptive_odbc.c
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: team/group/newcdr/cel/cel_adaptive_odbc.c
------------------------------------------------------------------------------
    svn:keywords = Author Id Date Revision

Propchange: team/group/newcdr/cel/cel_adaptive_odbc.c
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: team/group/newcdr/cel/cel_pgsql.c
URL: http://svn.digium.com/view/asterisk/team/group/newcdr/cel/cel_pgsql.c?view=diff&rev=166903&r1=166902&r2=166903
==============================================================================
--- team/group/newcdr/cel/cel_pgsql.c (original)
+++ team/group/newcdr/cel/cel_pgsql.c Tue Dec 30 14:21:26 2008
@@ -1,13 +1,13 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2007
+ * Copyright (C) 2008
  *
  * Steve Murphy - adapted to CEL, from:
  * Matthew D. Hardeman <mhardemn at papersoft.com> 
  * Adapted from the MySQL CDR logger originally by James Sharp 
  *
- * Modified April, 2007
+ * Modified April, 2007; Dec, 2008
  * Steve Murphy <murf at digium.com>
 
  * Modified September 2003
@@ -67,6 +67,7 @@
 static char *config = "cel_pgsql.conf";
 static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword = NULL, *pgdbport = NULL, *table = NULL;
 static int connected = 0;
+static int maxsize = 512, maxsize2 = 512;
 
 AST_MUTEX_DEFINE_STATIC(pgsql_lock);
 
@@ -74,10 +75,48 @@
 static PGresult	*result = NULL;
 static struct ast_event_sub *event_sub = 0;
 
+struct columns {
+        char *name;
+        char *type;
+        int len;
+        unsigned int notnull:1;
+        unsigned int hasdefault:1;
+        AST_RWLIST_ENTRY(columns) list;
+};
+
+static AST_RWLIST_HEAD_STATIC(psql_columns, columns);
+
+#define LENGTHEN_BUF1(size)                                               \
+	do {																\
+		/* Lengthen buffer, if necessary */								\
+		if (ast_str_strlen(sql) + size + 1 > ast_str_size(sql)) {		\
+			if (ast_str_make_space(&sql, ((ast_str_size(sql) + size + 3) / 512 + 1) * 512) != 0) { \
+				ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR failed.\n"); \
+				ast_free(sql);											\
+				ast_free(sql2);											\
+				AST_RWLIST_UNLOCK(&psql_columns);						\
+				return;													\
+			}															\
+		}																\
+	} while (0)
+
+#define LENGTHEN_BUF2(size)                               \
+	do {																\
+		if (ast_str_strlen(sql2) + size + 1 > ast_str_size(sql2)) {		\
+			if (ast_str_make_space(&sql2, ((ast_str_size(sql2) + size + 3) / 512 + 1) * 512) != 0) { \
+				ast_log(LOG_ERROR, "Unable to allocate sufficient memory.  Insert CDR failed.\n"); \
+				ast_free(sql);											\
+				ast_free(sql2);											\
+				AST_RWLIST_UNLOCK(&psql_columns);						\
+				return;													\
+			}															\
+		}																\
+	} while (0)
+
 static void pgsql_log(const struct ast_event *event, void *userdata)
 {
 	struct ast_tm tm;
-	char sqlcmd[2048] = "", timestr[128];
+	char timestr[128];
 	char *pgerror;
 	enum ast_cel_eventtype eventtype;
 	const char *userdefname = 0;
@@ -123,120 +162,211 @@
 		} else {
 			pgerror = PQerrorMessage(conn);
 			ast_log(LOG_ERROR, "cel_pgsql: Unable to connect to database server %s.  Calls will not be logged!\n", pghostname);
-                        ast_log(LOG_ERROR, "cel_pgsql: Reason: %s\n", pgerror);
+			ast_log(LOG_ERROR, "cel_pgsql: Reason: %s\n", pgerror);
+			PQfinish(conn);
+			conn = NULL;
 		}
 	}
 	if (connected) {
-		char *cidname_esc=NULL, *exten_esc=NULL, *context_esc=NULL, *channel_esc=NULL, *app_esc=NULL, *appdata_esc=NULL, *linkedid_esc=NULL;
-		char *uniqueid_esc=NULL, *cidnum_esc=NULL, *cidani_esc=NULL, *cidrdnis_esc=NULL, *ciddnid_esc=NULL, *accountcode_esc, *userfield_esc, *peer_esc;
-
-		/* Maximum space needed would be if all characters needed to be escaped, plus a trailing NULL */
-		if ((cidname_esc = alloca(strlen(cid_name) * 2 + 1)) != NULL) {
-			PQescapeString(cidname_esc, cid_name, strlen(cid_name));
-		}
-		if ((cidnum_esc = alloca(strlen(cid_num) * 2 + 1)) != NULL) {
-			PQescapeString(cidnum_esc, cid_num, strlen(cid_num));
-		}
-		if ((cidani_esc = alloca(strlen(cid_ani) * 2 + 1)) != NULL) {
-			PQescapeString(cidani_esc, cid_ani, strlen(cid_ani));
-		}
-		if ((cidrdnis_esc = alloca(strlen(cid_rdnis) * 2 + 1)) != NULL) {
-			PQescapeString(cidrdnis_esc, cid_rdnis, strlen(cid_rdnis));
-		}
-		if ((ciddnid_esc = alloca(strlen(cid_dnid) * 2 + 1)) != NULL) {
-			PQescapeString(ciddnid_esc, cid_dnid, strlen(cid_dnid));
-		}
-		if ((context_esc = alloca(strlen(context) * 2 + 1)) != NULL) {
-			PQescapeString(context_esc, context, strlen(context));
-		}
-		if ((channel_esc = alloca(strlen(channame) * 2 + 1)) != NULL) {
-			PQescapeString(channel_esc, channame, strlen(channame));
-		}
-		if ((app_esc = alloca(strlen(appname) * 2 + 1)) != NULL) {
-			PQescapeString(app_esc, appname, strlen(appname));
-		}
-		if ((appdata_esc = alloca(strlen(appdata) * 2 + 1)) != NULL) {
-			PQescapeString(appdata_esc, appdata, strlen(appdata));
-		}
-		if ((uniqueid_esc = alloca(strlen(uniqueid) * 2 + 1)) != NULL) {
-			PQescapeString(uniqueid_esc, uniqueid, strlen(uniqueid));
-		}
-		if ((linkedid_esc = alloca(strlen(linkedid) * 2 + 1)) != NULL) {
-			PQescapeString(linkedid_esc, linkedid, strlen(linkedid));
-		}
-		if ((accountcode_esc = alloca(strlen(accountcode) * 2 + 1)) != NULL) {
-			PQescapeString(accountcode_esc, accountcode, strlen(accountcode));
-		}
-		if ((userfield_esc = alloca(strlen(userfield) * 2 + 1)) != NULL) {
-			PQescapeString(userfield_esc, userfield, strlen(userfield));
-		}
-		if ((peer_esc = alloca(strlen(peer) * 2 + 1)) != NULL) {
-			PQescapeString(peer_esc, peer, strlen(peer));
-		}
-		/* Check for all alloca failures above at once */
-		if ((!cidname_esc) || (!context_esc) || (!channel_esc) || (!app_esc) || (!appdata_esc) || (!uniqueid_esc) || (!linkedid_esc)
-			|| (!ciddnid_esc) || (!cidrdnis_esc) || (!cidani_esc) || (!cidnum_esc)) {
-			ast_log(LOG_ERROR, "cel_pgsql:  Out of memory error (insert fails)\n");
-			ast_mutex_unlock(&pgsql_lock);
+		struct columns *cur;
+		struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2);
+		char buf[257], escapebuf[513];
+		const char *value;
+		int first = 1;
+
+		if (!sql || !sql2) {
+			if (sql) {
+				ast_free(sql);
+			}
+			if (sql2) {
+				ast_free(sql2);
+			}
 			return;
 		}
-		ast_debug(2, "cel_pgsql: inserting a CEL record.\n");
-		snprintf(sqlcmd,sizeof(sqlcmd),"INSERT INTO %s (eventtime,cidname,cidnum,cidani,cidrdnis,ciddnid,exten,context,channel,"
-				 "app,appdata,amaflags,accountcode,uniqueid,userfield,peer,linkedid) VALUES"
-				 " ('%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%s','%d,'%s','%s','%s','%s','%s')",
-				 table,timestr,cidname_esc,cidnum_esc, cidani_esc, cidrdnis_esc, ciddnid_esc, 
-				 exten_esc, context_esc,channel_esc, app_esc, appdata_esc,
-				 amaflag, accountcode_esc, uniqueid_esc, userfield_esc, peer_esc,linkedid_esc);
 		
-		ast_debug(3, "cel_pgsql: SQL command executed:  %s\n",sqlcmd);
-
+		ast_str_set(&sql, 0, "INSERT INTO %s (", table);
+		ast_str_set(&sql2, 0, " VALUES (");
+
+		AST_RWLIST_RDLOCK(&psql_columns);
+		AST_RWLIST_TRAVERSE(&psql_columns, cur, list) {
+			LENGTHEN_BUF1(strlen(cur->name) + 2);
+			ast_str_append(&sql, 0, "%s\"%s\"", first ? "" : ",", cur->name);
+			
+			if (strcmp(cur->name, "eventtime") == 0) {
+				if (strncmp(cur->type, "int", 3) == 0) {
+					LENGTHEN_BUF2(13);
+					ast_str_append(&sql2, 0, "%s%ld", first ? "" : ",", eventtime.tv_sec);
+				} else if (strncmp(cur->type, "float", 5) == 0) {
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)eventtime.tv_sec + (double)eventtime.tv_usec / 1000000.0);
+				} else {
+					/* char, hopefully */
+					LENGTHEN_BUF2(31);
+					ast_localtime(&eventtime, &tm, NULL);
+					ast_strftime(buf, sizeof(buf), DATE_FORMAT, &tm);
+					ast_str_append(&sql2, 0, "%s%s", first ? "" : ",", buf);
+				}
+			} else if (strcmp(cur->name, "eventtype") == 0) {
+				if (cur->type[0] == 'i') {
+					/* Get integer, no need to escape anything */
+					LENGTHEN_BUF2(5);
+					ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", (int)eventtype);
+				} else if (strncmp(cur->type, "float", 5) == 0) {
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s%f", first ? "" : ",", (double)eventtype);
+				} else {
+					/* Char field, probably */
+					char *t2 = ast_cel_eventtype2str(eventtype);
+					LENGTHEN_BUF2(strlen(t2)+1);
+					ast_str_append(&sql2, 0, "%s'%s'", first ? "" : ",", t2);
+				}
+			} else if (strcmp(cur->name, "amaflags") == 0) {
+				if (strncmp(cur->type, "int", 3) == 0) {
+					/* Integer, no need to escape anything */
+					LENGTHEN_BUF2(13);
+					ast_str_append(&sql2, 0, "%s%d", first ? "" : ",", amaflag);
+				} else {
+					/* Although this is a char field, there are no special characters in the values for these fields */
+					LENGTHEN_BUF2(31);
+					ast_str_append(&sql2, 0, "%s'%d'", first ? "" : ",", amaflag);
+				}
+			} else {
+				/* Arbitrary field, could be anything */
+				if (strcmp(cur->name, "userdeftype") == 0) {
+					value = userdefname;
+				} else if (strcmp(cur->name, "cid_name") == 0) {
+					value = cid_name;
+				} else if (strcmp(cur->name, "cid_num") == 0) {
+					value = cid_num;
+				} else if (strcmp(cur->name, "cid_ani") == 0) {
+					value = cid_ani;
+				} else if (strcmp(cur->name, "cid_rdnis") == 0) {
+					value = cid_rdnis;
+				} else if (strcmp(cur->name, "cid_dnid") == 0) {
+					value = cid_dnid;
+				} else if (strcmp(cur->name, "exten") == 0) {
+					value = exten;
+				} else if (strcmp(cur->name, "context") == 0) {
+					value = context;
+				} else if (strcmp(cur->name, "channame") == 0) {
+					value = channame;
+				} else if (strcmp(cur->name, "appname") == 0) {

[... 533 lines stripped ...]



More information about the asterisk-commits mailing list