From 797d633139a52a87736c04b71e31b1cb66e21e08 Mon Sep 17 00:00:00 2001
From: Richard Mudgett <rmudgett@digium.com>
Date: Wed, 1 Feb 2012 17:42:15 +0000
Subject: [PATCH] Remove inconsistency in CEL eventtype for user defined
 events.

The CEL eventtype field for ODBC and PGSQL backends should be USER_DEFINED
instead of the user defined event name supplied by the CELGenUserEvent
application.  If the field is output as a number, the user defined name
does not have a value and is always output as 21 for USER_DEFINED and the
userdeftype field would be required to supply the user defined name.

The following CEL backends (cel_odbc, cel_pgsql, cel_custom, cel_manager,
and cel_sqlite3_custom) can be independently configured to remove this
inconsistency.

* Allows cel_manager, cel_custom, and cel_sqlite3_custom to behave the
same way.

(closes issue ASTERISK-17189)
Reported by: Bryant Zimmerman

Review: https://reviewboard.asterisk.org/r/1669/


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@353648 65c4cc65-6c06-0410-ace0-fbb531ad65f3
---
 cel/cel_manager.c                      | 34 +++++++++++++++++++++++---
 cel/cel_odbc.c                         | 26 +++++++++++++++++++-
 cel/cel_pgsql.c                        | 33 +++++++++++++++++++------
 cel/cel_tds.c                          | 12 +++++----
 configs/cel.conf.sample                |  7 ++++++
 configs/cel_custom.conf.sample         |  1 +
 configs/cel_odbc.conf.sample           |  9 ++++++-
 configs/cel_pgsql.conf.sample          |  5 ++++
 configs/cel_sqlite3_custom.conf.sample |  1 +
 main/cel.c                             | 14 +++++++----
 10 files changed, 119 insertions(+), 23 deletions(-)

diff --git a/cel/cel_manager.c b/cel/cel_manager.c
index 76ca48bbb7..e1d0dc148c 100644
--- a/cel/cel_manager.c
+++ b/cel/cel_manager.c
@@ -49,14 +49,25 @@ static const char DATE_FORMAT[] = "%Y-%m-%d %T";
 
 static const char CONF_FILE[] = "cel.conf";
 
+/*! \brief AMI CEL is off by default */
+#define CEL_AMI_ENABLED_DEFAULT		0
+
 static int enablecel;
 
+/*! \brief show_user_def is off by default */
+#define CEL_SHOW_USERDEF_DEFAULT	0
+
+/*! TRUE if we should set the EventName header to USER_DEFINED on user events. */
+static unsigned char cel_show_user_def;
+
 static struct ast_event_sub *event_sub;
 
 static void manager_log(const struct ast_event *event, void *userdata)
 {
 	struct ast_tm timeresult;
 	char start_time[80] = "";
+	char user_defined_header[160];
+	const char *event_name;
 	struct ast_cel_event_record record = {
 		.version = AST_CEL_EVENT_RECORD_VERSION,
 	};
@@ -72,6 +83,17 @@ static void manager_log(const struct ast_event *event, void *userdata)
 	ast_localtime(&record.event_time, &timeresult, NULL);
 	ast_strftime(start_time, sizeof(start_time), DATE_FORMAT, &timeresult);
 
+	event_name = record.event_name;
+	user_defined_header[0] = '\0';
+	if (record.event_type == AST_CEL_USER_DEFINED) {
+		if (cel_show_user_def) {
+			snprintf(user_defined_header, sizeof(user_defined_header),
+				"UserDefType: %s\r\n", record.user_defined_name);
+		} else {
+			event_name = record.user_defined_name;
+		}
+	}
+
 	manager_event(EVENT_FLAG_CALL, "CEL",
 		"EventName: %s\r\n"
 		"AccountCode: %s\r\n"
@@ -92,8 +114,9 @@ static void manager_log(const struct ast_event *event, void *userdata)
 		"Userfield: %s\r\n"
 		"Peer: %s\r\n"
 		"PeerAccount: %s\r\n"
+		"%s"
 		"Extra: %s\r\n",
-		record.event_name,
+		event_name,
 		record.account_code,
 		record.caller_id_num,
 		record.caller_id_name,
@@ -112,6 +135,7 @@ static void manager_log(const struct ast_event *event, void *userdata)
 		record.user_field,
 		record.peer,
 		record.peer_account,
+		user_defined_header,
 		record.extra);
 }
 
@@ -121,7 +145,8 @@ static int load_config(int reload)
 	struct ast_config *cfg;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
 	struct ast_variable *v;
-	int newenablecel = 0;
+	int newenablecel = CEL_AMI_ENABLED_DEFAULT;
+	int new_cel_show_user_def = CEL_SHOW_USERDEF_DEFAULT;
 
 	cfg = ast_config_load(CONF_FILE, config_flags);
 	if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
@@ -141,7 +166,9 @@ static int load_config(int reload)
 
 		for (v = ast_variable_browse(cfg, cat); v; v = v->next) {
 			if (!strcasecmp(v->name, "enabled")) {
-				newenablecel = ast_true(v->value);
+				newenablecel = ast_true(v->value) ? 1 : 0;
+			} else if (!strcasecmp(v->name, "show_user_defined")) {
+				new_cel_show_user_def = ast_true(v->value) ? 1 : 0;
 			} else {
 				ast_log(LOG_NOTICE, "Unknown option '%s' specified "
 						"for cel_manager.\n", v->name);
@@ -151,6 +178,7 @@ static int load_config(int reload)
 
 	ast_config_destroy(cfg);
 
+	cel_show_user_def = new_cel_show_user_def;
 	if (enablecel && !newenablecel) {
 		if (event_sub) {
 			event_sub = ast_event_unsubscribe(event_sub);
diff --git a/cel/cel_odbc.c b/cel/cel_odbc.c
index 223cb18c99..1a5427169b 100644
--- a/cel/cel_odbc.c
+++ b/cel/cel_odbc.c
@@ -53,6 +53,12 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #define	CONFIG	"cel_odbc.conf"
 static struct ast_event_sub *event_sub = NULL;
 
+/*! \brief show_user_def is off by default */
+#define CEL_SHOW_USERDEF_DEFAULT	0
+
+/*! TRUE if we should set the eventtype field to USER_DEFINED on user events. */
+static unsigned char cel_show_user_def;
+
 /* Optimization to reduce number of memory allocations */
 static int maxsize = 512, maxsize2 = 512;
 
@@ -103,7 +109,20 @@ static int load_config(void)
 		return -1;
 	}
 
+	/* Process the general category */
+	cel_show_user_def = CEL_SHOW_USERDEF_DEFAULT;
+	for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
+		if (!strcasecmp(var->name, "show_user_defined")) {
+			cel_show_user_def = ast_true(var->value) ? 1 : 0;
+		} else {
+			/* Unknown option name. */
+		}
+	}
+
 	for (catg = ast_category_browse(cfg, NULL); catg; catg = ast_category_browse(cfg, catg)) {
+		if (!strcasecmp(catg, "general")) {
+			continue;
+		}
 		var = ast_variable_browse(cfg, catg);
 		if (!var)
 			continue;
@@ -476,7 +495,12 @@ static void odbc_log(const struct ast_event *event, void *userdata)
 					 * form (but only when we're dealing with a character-based field).
 					 */
 					if (strcasecmp(entry->name, "eventtype") == 0) {
-						snprintf(colbuf, sizeof(colbuf), "%s", record.event_name);
+						const char *event_name;
+
+						event_name = (!cel_show_user_def
+							&& record.event_type == AST_CEL_USER_DEFINED)
+							? record.user_defined_name : record.event_name;
+						snprintf(colbuf, sizeof(colbuf), "%s", event_name);
 					}
 
 					/* Truncate too-long fields */
diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c
index 99374a824e..f7676f88ea 100644
--- a/cel/cel_pgsql.c
+++ b/cel/cel_pgsql.c
@@ -63,6 +63,12 @@ static char *pghostname = NULL, *pgdbname = NULL, *pgdbuser = NULL, *pgpassword
 static int connected = 0;
 static int maxsize = 512, maxsize2 = 512;
 
+/*! \brief show_user_def is off by default */
+#define CEL_SHOW_USERDEF_DEFAULT	0
+
+/*! TRUE if we should set the eventtype field to USER_DEFINED on user events. */
+static unsigned char cel_show_user_def;
+
 AST_MUTEX_DEFINE_STATIC(pgsql_lock);
 
 static PGconn	*conn = NULL;
@@ -70,12 +76,12 @@ static PGresult	*result = NULL;
 static struct ast_event_sub *event_sub = NULL;
 
 struct columns {
-        char *name;
-        char *type;
-        int len;
-        unsigned int notnull:1;
-        unsigned int hasdefault:1;
-        AST_RWLIST_ENTRY(columns) list;
+	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);
@@ -185,8 +191,13 @@ static void pgsql_log(const struct ast_event *event, void *userdata)
 					ast_str_append(&sql2, 0, "%s%f", SEP, (double) record.event_type);
 				} else {
 					/* Char field, probably */
-					LENGTHEN_BUF2(strlen(record.event_name) + 1);
-					ast_str_append(&sql2, 0, "%s'%s'", SEP, record.event_name);
+					const char *event_name;
+
+					event_name = (!cel_show_user_def
+						&& record.event_type == AST_CEL_USER_DEFINED)
+						? record.user_defined_name : record.event_name;
+					LENGTHEN_BUF2(strlen(event_name) + 1);
+					ast_str_append(&sql2, 0, "%s'%s'", SEP, event_name);
 				}
 			} else if (strcmp(cur->name, "amaflags") == 0) {
 				if (strncmp(cur->type, "int", 3) == 0) {
@@ -449,6 +460,10 @@ static int process_my_load_module(struct ast_config *cfg)
 	if (!(table = ast_strdup(tmp))) {
 		return AST_MODULE_LOAD_DECLINE;
 	}
+	cel_show_user_def = CEL_SHOW_USERDEF_DEFAULT;
+	if ((tmp = ast_variable_retrieve(cfg, "global", "show_user_defined"))) {
+		cel_show_user_def = ast_true(tmp) ? 1 : 0;
+	}
 	if (option_debug) {
 		if (ast_strlen_zero(pghostname)) {
 			ast_debug(3, "cel_pgsql: using default unix socket\n");
@@ -460,6 +475,8 @@ static int process_my_load_module(struct ast_config *cfg)
 		ast_debug(3, "cel_pgsql: got dbname of %s\n", pgdbname);
 		ast_debug(3, "cel_pgsql: got password of %s\n", pgpassword);
 		ast_debug(3, "cel_pgsql: got sql table name of %s\n", table);
+		ast_debug(3, "cel_pgsql: got show_user_defined of %s\n",
+			cel_show_user_def ? "Yes" : "No");
 	}
 
 	conn = PQsetdbLogin(pghostname, pgdbport, NULL, NULL, pgdbname, pgdbuser, pgpassword);
diff --git a/cel/cel_tds.c b/cel/cel_tds.c
index f5686c9b0c..df2b573bf2 100644
--- a/cel/cel_tds.c
+++ b/cel/cel_tds.c
@@ -19,17 +19,17 @@
  * \brief FreeTDS CEL logger
  *
  * See also
- * \arg \ref Config_cdr
+ * \arg \ref Config_cel
  * \arg http://www.freetds.org/
- * \ingroup cdr_drivers
+ * \ingroup cel_drivers
  */
 
 /*! \verbatim
  *
- * Table Structure for `cdr`
+ * Table Structure for `cel`
  *
 
-CREATE TABLE [dbo].[cdr] (
+CREATE TABLE [dbo].[cel] (
 	[accountcode] [varchar] (20) NULL ,
 	[cidname] [varchar] (80) NULL ,
 	[cidnum] [varchar] (80) NULL ,
@@ -204,7 +204,9 @@ retry:
 		")",
 		settings->table, accountcode_ai, clidnum_ai, clid_ai, cidani_ai, cidrdnis_ai,
 		ciddnid_ai, exten_ai, context_ai, channel_ai, app_ai, appdata_ai, start,
-		record.event_name, ast_cel_get_ama_flag_name(record.amaflag), uniqueid_ai, linkedid_ai,
+		(record.event_type == AST_CEL_USER_DEFINED)
+			? record.user_defined_name : record.event_name,
+		ast_cel_get_ama_flag_name(record.amaflag), uniqueid_ai, linkedid_ai,
 		userfield_ai, peer_ai);
 
 	if (erc == FAIL) {
diff --git a/configs/cel.conf.sample b/configs/cel.conf.sample
index a17cf68810..7bd7f89f08 100644
--- a/configs/cel.conf.sample
+++ b/configs/cel.conf.sample
@@ -105,6 +105,13 @@ events=APP_START,CHAN_START,CHAN_END,ANSWER,HANGUP,BRIDGE_START,BRIDGE_END
 ; Default value:   no
 ;enabled=yes
 
+; Use 'show_user_defined' to put "USER_DEFINED" in the EventName header,
+; instead of (by default) just putting the user defined event name there.
+; When enabled the UserDefType header is added for user defined events to
+; provide the user defined event name.
+;
+;show_user_defined=yes
+
 ;
 ; RADIUS CEL Backend 
 ;
diff --git a/configs/cel_custom.conf.sample b/configs/cel_custom.conf.sample
index 59c33dc542..126248acaf 100644
--- a/configs/cel_custom.conf.sample
+++ b/configs/cel_custom.conf.sample
@@ -24,6 +24,7 @@
 ;
 ;    eventtype   - The name of the CEL event.
 ;    eventtime   - The timestamp of the CEL event.
+;    eventenum   - Like eventtype but is "USER_DEFINED" for a user defined event.
 ;    userdeftype - User defined event type name from CELGenUserEvent().
 ;    eventextra  - Extra data included with this CEL event, typically along with
 ;                  an event of type USER_DEFINED from CELGenUserEvent().
diff --git a/configs/cel_odbc.conf.sample b/configs/cel_odbc.conf.sample
index 640de4fb62..1c7ff50954 100644
--- a/configs/cel_odbc.conf.sample
+++ b/configs/cel_odbc.conf.sample
@@ -2,6 +2,13 @@
 ; Asterisk Channel Event Logging (CEL) - Adaptive ODBC Backend
 ;
 
+; General module options category.
+[general]
+; Use 'show_user_defined' to put "USER_DEFINED" in the eventtype field,
+; instead of (by default) just putting the user defined event name there.
+;
+;show_user_defined=yes
+
 ; This configuration defines the connections and tables for which CEL records
 ; may be populated.  Each context specifies a different CEL table to be used.
 ;
@@ -90,7 +97,7 @@
 ;alias dst => dest
 ;alias dstchannel => dest_channel
 
-; Any filter specified MUST match exactly or the CE will be discarded
+; Any filter specified MUST match exactly or the event will be discarded
 ;filter accountcode => somename
 ;filter src => 123
 
diff --git a/configs/cel_pgsql.conf.sample b/configs/cel_pgsql.conf.sample
index d71fcc6be3..cc9b9ff91a 100644
--- a/configs/cel_pgsql.conf.sample
+++ b/configs/cel_pgsql.conf.sample
@@ -54,6 +54,11 @@
 ;	extra
 
 [global]
+; Use 'show_user_defined' to put "USER_DEFINED" in the eventtype field,
+; instead of (by default) just putting the user defined event name there.
+;
+;show_user_defined=yes
+
 ;hostname=localhost
 ;port=5432
 ;dbname=asterisk
diff --git a/configs/cel_sqlite3_custom.conf.sample b/configs/cel_sqlite3_custom.conf.sample
index 14f2dd2281..2d9a24fc7b 100644
--- a/configs/cel_sqlite3_custom.conf.sample
+++ b/configs/cel_sqlite3_custom.conf.sample
@@ -11,6 +11,7 @@
 ;
 ;    eventtype   - The name of the CEL event.
 ;    eventtime   - The timestamp of the CEL event.
+;    eventenum   - Like eventtype but is "USER_DEFINED" for a user defined event.
 ;    userdeftype - User defined event type name from CELGenUserEvent().
 ;    eventextra  - Extra data included with this CEL event, typically along with
 ;                  an event of type USER_DEFINED from CELGenUserEvent().
diff --git a/main/cel.c b/main/cel.c
index 6e8215f202..f7e28f0efd 100644
--- a/main/cel.c
+++ b/main/cel.c
@@ -402,6 +402,7 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
 {
 	struct varshead *headp;
 	struct ast_var_t *newvariable;
+	const char *mixed_name;
 	char timebuf[30];
 	struct ast_channel *tchan;
 	struct ast_cel_event_record record = {
@@ -422,7 +423,9 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
 	}
 
 	/* next, fill the channel with their data */
-	if ((newvariable = ast_var_assign("eventtype", record.event_name))) {
+	mixed_name = (record.event_type == AST_CEL_USER_DEFINED)
+		? record.user_defined_name : record.event_name;
+	if ((newvariable = ast_var_assign("eventtype", mixed_name))) {
 		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
 	}
 
@@ -439,6 +442,9 @@ struct ast_channel *ast_cel_fabricate_channel_from_event(const struct ast_event
 		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
 	}
 
+	if ((newvariable = ast_var_assign("eventenum", record.event_name))) {
+		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
+	}
 	if ((newvariable = ast_var_assign("userdeftype", record.user_defined_name))) {
 		AST_LIST_INSERT_HEAD(headp, newvariable, entries);
 	}
@@ -598,13 +604,11 @@ int ast_cel_fill_record(const struct ast_event *e, struct ast_cel_event_record *
 	r->event_time.tv_sec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME);
 	r->event_time.tv_usec = ast_event_get_ie_uint(e, AST_EVENT_IE_CEL_EVENT_TIME_USEC);
 
-	r->user_defined_name = "";
-
+	r->event_name = ast_cel_get_type_name(r->event_type);
 	if (r->event_type == AST_CEL_USER_DEFINED) {
 		r->user_defined_name = ast_event_get_ie_str(e, AST_EVENT_IE_CEL_USEREVENT_NAME);
-		r->event_name = r->user_defined_name;
 	} else {
-		r->event_name = ast_cel_get_type_name(r->event_type);
+		r->user_defined_name = "";
 	}
 
 	r->caller_id_name   = S_OR(ast_event_get_ie_str(e, AST_EVENT_IE_CEL_CIDNAME), "");
-- 
GitLab