[asterisk-commits] murf: branch murf/cel2cdr r179217 - in /team/murf/cel2cdr: cel/ utils/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sat Feb 28 11:30:03 CST 2009
Author: murf
Date: Sat Feb 28 11:30:00 2009
New Revision: 179217
URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=179217
Log:
check in initial pot-shots at the most important stuff... the stuff that will make testing this stuff easy.
Added:
team/murf/cel2cdr/cel/
team/murf/cel2cdr/cel/cel_cel2cdr.c (with props)
team/murf/cel2cdr/utils/csv2ev.c (with props)
Modified:
team/murf/cel2cdr/utils/Makefile
Added: team/murf/cel2cdr/cel/cel_cel2cdr.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cel2cdr/cel/cel_cel2cdr.c?view=auto&rev=179217
==============================================================================
--- team/murf/cel2cdr/cel/cel_cel2cdr.c (added)
+++ team/murf/cel2cdr/cel/cel_cel2cdr.c Sat Feb 28 11:30:00 2009
@@ -1,0 +1,144 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2009, Digium, Inc.
+ *
+ * Steve Murphy <murf at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/* for simple CDRs:
+ */
+
+#include "asterisk/dlinkedlists.h"
+#include "asterisk/hashtab.h"
+
+struct event_list_member
+{
+ struct ast_event *ev;
+ AST_DLLIST_ENTRY(event_list_member) list;
+};
+
+struct event_list
+{
+ char *linkedid; /* will be the channel name for simple CDR's; the linkedid for leg-based */
+
+ /* I'm trying to think of any other stuff I might need here... */
+
+ /* you know, maybe a DLL isn't so good here...
+ the events may not arrive in order, due to the
+ multiple thread nature of things. Mayhaps a priority
+ queue (rbtrees, or Russell's heap stuff...? We'll figure
+ it out soon. I think the requirements are these:
+ a. insert an element into the list in order by event
+ time should be pretty quick. Mostly, new events should
+ be appended to the end.
+ b. I should be able to 'monkey' around the list pretty
+ easily. Next(), Previous(), that sort of thing.
+ c. I think I'll be needing to remove chunks of the list
+ as they are 'used up' (a CDR posted). This should
+ be fast & painless
+ */
+ AST_DLLIST_ENTRY(event_list_member) list;
+};
+
+/* this hashtab is the central theme to the CDR approach.
+ Each event is filed into a list by their channel name (simple),
+ or by the linkedid (leg-based).
+*/
+static struct ast_hashtab *master_table = NULL;
+
+/* the funcs for hashing */
+
+static int table_compare_func(const void *a, const void *b)
+{
+ struct event_list *ev_a = a;
+ struct event list *ev_b = b;
+ return strcmp(ev_b->linkedid, ev_b->linkedid);
+}
+
+static unsigned int table_hash_func(const void *obj)
+{
+ struct event_list *obj_a = obj;
+ ast_hashtab_hash_string(obj_a->linkedid);
+}
+
+/* destruction is really boring stuff....
+ until it doesn't work, or doesn't work right! */
+
+void destroy_event_list_member(struct event_list_member *m)
+{
+ ast_event_destroy(m->ev);
+ m->ev = NULL;
+ free(m);
+}
+
+void destroy_event_list(struct event_list *l)
+{
+ struct event_list_member *m;
+
+ AST_DLLIST_TRAVERSE_SAFE_BEGIN(&l->list, m, list) {
+ AST_DLLIST_REMOVE_CURRENT(list);
+ destroy_event_list_member(m);
+ }
+ AST_DLLIST_TRAVERSE_SAFE_END;
+ free(l->linkedid);
+ l->linkedid = NULL;
+ free(l);
+}
+
+
+/* mode == 0; SIMPLE
+ mode == 1; LEG_BASED
+*/
+
+enum cdr_mode_type { CEL2CDR_MODE_SIMPLE = 0, CEL2CDR_MODE_LEGBASED = 1 } ;
+
+enum cdr_mode_type cdr_mode = CEL2CDR_MODE_SIMPLE;
+static int cel2cdr_enabled = 0;
+
+static mod_load_func()
+{
+ /* read the config file, set all the control variables. */
+
+ /* set up the master table */
+ if (cel2cdr_enabled) {
+ if (!master_table) {
+ master_table = ast_hashtab_create(1001, table_compare_func, table_resize_func,
+ table_newsize_func, table_hash_func, 1 /* do locking */);
+ } else {
+ /* this shouldn't happen? or should I just remove all the
+ stuff from the table and leave it initialized? */
+ }
+ }
+}
+
+static mod_unload_func()
+{
+ if (master_table) {
+ ast_hashtab_destroy(master_table, destroy_event_list);
+ master_table = NULL;
+ }
+}
+
+
+void cel2cdr_handle_event(const struct ast_event *event, void *userdata)
+{
+ if (cel2cdr_enabled) {
+ if (cdr_mode == CEL2CDR_MODE_SIMPLE) {
+ /* save up start, answer, end event times and on END
+ events, generate a CDR and post it */
+ } else { /* then LEGBASED by elimination! */
+
+ }
+ }
+}
Propchange: team/murf/cel2cdr/cel/cel_cel2cdr.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/murf/cel2cdr/cel/cel_cel2cdr.c
------------------------------------------------------------------------------
svn:keywords = Author Id Date Revision
Propchange: team/murf/cel2cdr/cel/cel_cel2cdr.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: team/murf/cel2cdr/utils/Makefile
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cel2cdr/utils/Makefile?view=diff&rev=179217&r1=179216&r2=179217
==============================================================================
--- team/murf/cel2cdr/utils/Makefile (original)
+++ team/murf/cel2cdr/utils/Makefile Sat Feb 28 11:30:00 2009
@@ -16,7 +16,7 @@
.PHONY: clean all uninstall
-ALL_UTILS:=astman smsq stereorize streamplayer muted check_expr hashtest2 hashtest astcanary refcounter aelparse conf2ael
+ALL_UTILS:=astman smsq stereorize streamplayer muted check_expr hashtest2 hashtest astcanary refcounter aelparse conf2ael csv2cdr
UTILS:=$(ALL_UTILS)
LIBS += $(BKTR_LIB) # astobj2 with devmode uses backtrace
@@ -132,10 +132,15 @@
$(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
$(CMD_PREFIX) cp "$<" "$@"
+csv2ev.o : csv2ev.c
+
ael_main.o: ASTCFLAGS+=-DSTANDALONE
aelparse.o: ASTCFLAGS+=-I$(ASTTOPDIR)/res -DSTANDALONE -Wno-unused
aelparse: aelparse.o aelbison.o pbx_ael.o hashtab.o ael_main.o ast_expr2f.o ast_expr2.o strcompat.o pval.o extconf.o
+
+csv2cdr : csv2ev.o
+
astobj2.c: $(ASTTOPDIR)/main/astobj2.c
$(ECHO_PREFIX) echo " [CP] $(subst $(ASTTOPDIR)/,,$<) -> $@"
Added: team/murf/cel2cdr/utils/csv2ev.c
URL: http://svn.digium.com/svn-view/asterisk/team/murf/cel2cdr/utils/csv2ev.c?view=auto&rev=179217
==============================================================================
--- team/murf/cel2cdr/utils/csv2ev.c (added)
+++ team/murf/cel2cdr/utils/csv2ev.c Sat Feb 28 11:30:00 2009
@@ -1,0 +1,348 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2009, Digium, Inc.
+ *
+ * Steve Murphy <murf at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*! \file
+ *
+ * \brief Routines ...routines to read in a csv formatted cel event file, and generate
+ * event calls for the cel2cdr engine(s).
+ *
+ * \author Steve Murphy <murf at digium.com>
+ */
+
+#include "asterisk/event.h" /* which will include the event_defs.h also */
+#include "asterisk/linkedlists.h"
+#include "asterisk/extconf.h"
+#include "asterisk/cel.h"
+
+/* a simple linked list will represent what the user put in his cel_custom
+ config file... basically, we need the order of each field type.
+ we can then rocket the data off to the event calls */
+*/
+
+struct csv_list_mem
+{
+ enum ast_event_ie_type type;
+ AST_LIST_ENTRY(csv_list_mem) list;
+};
+
+struct csv_list
+{
+ AST_LIST_HEAD_NOLOCK(list, csv_list_mem);
+};
+
+enum ast_event_ie_type csv2ev_str2eventietype(char *str)
+{
+ /* hmmm, could we do a perfect hash of some sort? */
+ /* later maybe */
+ if (!strcmp(str,"${eventtype}")) {
+ return AST_EVENT_IE_CEL_EVENT_TYPE;
+ } else if (!strcmp(str,"${eventtime}")) {
+ return AST_EVENT_IE_CEL_EVENT_TIME;
+ } else if (!strcmp(str,"${CALLERID(name)}")) {
+ return AST_EVENT_IE_CEL_CIDNAME;
+ } else if (!strcmp(str,"${CALLERID(num)}")) {
+ return AST_EVENT_IE_CEL_CIDNUM;
+ } else if (!strcmp(str,"${CALLERID(ANI)}")) {
+ return AST_EVENT_IE_CEL_CIDANI;
+ } else if (!strcmp(str,"${CALLERID(RDNIS)}")) {
+ return AST_EVENT_IE_CEL_CIDRDNIS;
+ } else if (!strcmp(str,"${CALLERID(DNID)}")) {
+ return AST_EVENT_IE_CEL_CIDDNID;
+ } else if (!strcmp(str,"${CHANNEL(exten)}")) {
+ return AST_EVENT_IE_CEL_EXTEN;
+ } else if (!strcmp(str,"${CHANNEL(context)}")) {
+ return AST_EVENT_IE_CEL_CONTEXT;
+ } else if (!strcmp(str,"${CHANNEL(channame)}")) {
+ return AST_EVENT_IE_CEL_CHANNAME;
+ } else if (!strcmp(str,"${CHANNEL(appname)}")) {
+ return AST_EVENT_IE_CEL_APPNAME;
+ } else if (!strcmp(str,"${CHANNEL(appdata)}")) {
+ return AST_EVENT_IE_CEL_APPDATA;
+ } else if (!strcmp(str,"${CHANNEL(amaflags)}")) {
+ return AST_EVENT_IE_CEL_AMAFLAGS;
+ } else if (!strcmp(str,"${CHANNEL(accountcode)}")) {
+ return AST_EVENT_IE_CEL_ACCTCODE;
+ } else if (!strcmp(str,"${CHANNEL(uniqueid)}")) {
+ return AST_EVENT_IE_CEL_UNIQUEID;
+ } else if (!strcmp(str,"${CHANNEL(userfield)}")) {
+ return AST_EVENT_IE_CEL_USERFIELD;
+ } else if (!strcmp(str,"${CHANNEL(peer)}")) {
+ return AST_EVENT_IE_CEL_PEER;
+ } else if (!strcmp(str,"${CHANNEL(linkedid)}")) {
+ return AST_EVENT_IE_CEL_LINKEDID;
+ } else if (!strcmp(str,"${CHANNEL(peeracct)}")) {
+ return AST_EVENT_IE_CEL_PEERACCT;
+ } else {
+ printf("Hey!!! I do not understand what the cel_custom.conf field entry '%s' means!\n", str);
+ return AST_EVENT_IE_CEL_EXTRA;
+ }
+}
+
+
+struct csv_list *parse_mappings(char *val)
+{
+ struct csv_list *x = calloc(sizeof(struct csv_list),1);
+ char *beg1, *end1;
+
+ if (!x) {
+ printf("Couldn't allocate a csv_list struct!\n");
+ return NULL;
+ }
+
+ if (*val == '"')
+ val++;
+ if (val[strlen(val)-1] == '"') {
+ strcat(val,",\""); /* now every field is ended with the same char sequence! */
+ }
+
+ while (beg1 = strstr(val,"\",\"")) {
+ *beg1 = 0;
+ /* val now points to the single entry, stripped of quotes */
+ struct csv_list_mem *m = calloc(sizeof(struct csv_list_mem),1);
+ if (!m) {
+ printf("Couldn't allocate a csv_list_mem struct!\n");
+ return NULL;
+ }
+ AST_LIST_INSERT_TAIL(x, m, list);
+ m->type = csv2ev_str2eventietype(val);
+ val = beg1+3;
+ }
+
+ return x;
+}
+
+char *get_mappings(char *fname, char **fname)
+{
+ /* open the cel_custom file and get the first mappings value */
+ localized_use_conf_dir();
+ struct ast_config *f = localized_config_load(fname);
+ if (f) {
+ struct ast_category *m = localized_category_get(f, "mappings");
+ if (m) {
+ /* get the first variable */
+ if (m->root) {
+ printf("Found '%s => %s' in mappings!\n", m->root->name, m->root->name);
+ *fname = m->root->name;
+ return m->root->val;
+ } else {
+ printf("Sorry, but the mappings category was empty!\n");
+ return NULL;
+ }
+ } else {
+ printf("Sorry, the cel_custom.conf file had no mappings category!\n");
+ return NULL;
+ }
+ } else {
+ printf("Sorry, no cel_custom.conf file was found!\n");
+ return NULL;
+ }
+}
+
+void csv2events(void)
+{
+
+ /* load the config file, then the csv file, and generate the events */
+ struct csv_list *csvlist, *csvptr;
+ char *fname;
+ char *mappings = get_mappings("cel_custom.conf", &fname);
+ if (mappings) {
+ csvlist = parse_mappings(char *val);
+ if (csvlist) {
+ /* OK, we know the order of each field. Watch out for usecs.
+ Now, let's open the log file and begin event generation */
+ FILE *f;
+ char filename[512];
+ char buf[2048], *r;
+
+ snprintf(filename, 512, "/var/log/asterisk/cel-custom/%s", fname);
+ f = fopen(filename, "r");
+ if (f) {
+ while (r=fgets(buf, sizeof(buf), f)) {
+ char *beg1, *val;
+ char *e_udef, *e_cid_name, *e_cid_num, *e_cid_ani, *e_cid_rdnis,
+ *e_cid_dnid, *e_exten, *e_context, *e_name, *e_appl, *e_appdata, *e_acctcode,
+ *e_peeracct, *e_uniqueid, *e_linkedid, *e_userfield, *e_extra, *e_peername;
+ unsigned int i_tvsec, i_tvusec, i_ama;
+ int i_type;
+ char *decptr;
+
+ if (buf[strlen(buf)-1] != '\n') {
+ printf("Buffer size of %d was not large enough; tossing out input\n");
+ fgets(buf, sizeof(buf), f); /* hopefully, that was all there's left! */
+ continue;
+ } else {
+ buf[strlen(buf)-1] = 0;
+ }
+ /* we have a complete line from the cel-custom file */
+ if (strlen(buf)+3 < sizeof(buf)) {
+ printf("Buffer size exceeded for line: skipping.\n");
+ continue;
+ }
+ strcat(buf,",\""); /* now every field ends with the same pattern */
+ if (buf[0] == '"') {
+ val = buf + 1;
+ } else {
+ val = buf;
+ }
+ /* the temptation is strong to not use the event code to
+ generate the event structs, so we don't have dependencies
+ on taskprocessors and who knows what else in the asterisk
+ core! */
+ csvptr = AST_LIST_FIRST(csvlist);
+ /* gather up the fields, and prepare for a the event call */
+ while (beg1 = strstr(val,"\",\"")) {
+ *beg1 = 0;
+ /* val now points to the single entry, stripped of quotes */
+ switch(csvptr->type)
+ {
+ case AST_EVENT_IE_CEL_EVENT_TYPE:
+ i_type = (int)ast_cel_str2eventtype(val);
+ if (i_type == -1) {
+ i_type = (int)CEL_USER_DEFINED;
+ e_udef = val;
+ } else {
+ e_udef = "";
+ }
+
+ break;
+ case AST_EVENT_IE_CEL_EVENT_TIME:
+ i_tvsec = strtol(val, NULL, 10);
+ decptr = strchr(val,'.');
+ if (decptr) {
+ i_tvusec = strlol(decptr+1, NULL, 10);
+ } else {
+ i_tvusec = 0;
+ }
+ break;
+ case AST_EVENT_IE_CEL_CIDNAME:
+ e_cid_name = val;
+ break;
+
+ case AST_EVENT_IE_CEL_CIDNUM:
+ e_cid_num = val;
+ break;
+
+ case AST_EVENT_IE_CEL_CIDANI:
+ e_cid_ani = val;
+ break;
+
+ case AST_EVENT_IE_CEL_CIDRDNIS:
+ e_cid_rdnis = val;
+ break;
+
+ case AST_EVENT_IE_CEL_CIDDNID:
+ e_cid_dnid = val;
+ break;
+
+ case AST_EVENT_IE_CEL_EXTEN:
+ e_exten = val;
+ break;
+
+ case AST_EVENT_IE_CEL_CONTEXT:
+ e_context = val;
+ break;
+
+ case AST_EVENT_IE_CEL_CHANNAME:
+ e_name = val;
+ break;
+
+ case AST_EVENT_IE_CEL_APPNAME:
+ e_appl = val;
+ break;
+
+ case AST_EVENT_IE_CEL_APPDATA:
+ e_appdata = val;
+ break;
+
+ case AST_EVENT_IE_CEL_AMAFLAGS:
+ i_ama = atoi(val);
+ break;
+
+ case AST_EVENT_IE_CEL_ACCTCODE:
+ e_acctcode = val;
+ break;
+
+ case AST_EVENT_IE_CEL_UNIQUEID:
+ e_uniqueid = val;
+ break;
+
+ case AST_EVENT_IE_CEL_USERFIELD:
+ e_userfield = val;
+ break;
+
+ case AST_EVENT_IE_CEL_PEER:
+ e_peername = val;
+ break;
+
+ case AST_EVENT_IE_CEL_LINKEDID:
+ e_linkedid = val;
+ break;
+
+ case AST_EVENT_IE_CEL_PEERACCT:
+ e_peeracct = val;
+ break;
+
+ case AST_EVENT_IE_CEL_EXTRA:
+ e_extra = val;
+ break;
+ }
+ csvptr = AST_LIST_NEXT(csvptr,list);
+ val = beg1+3;
+ }
+ /* this is a lot of trouble for a standalone to go to to pass this
+ info to the cdr generator, but... we want it to be the same interface
+ at that end, whether within asterisk, or in a standalone. No code
+ duplication that way. */
+ ev = ast_event_new(AST_EVENT_CEL,
+ AST_EVENT_IE_CEL_EVENT_TYPE, AST_EVENT_IE_PLTYPE_UINT, (unsigned int)i_type,
+ AST_EVENT_IE_CEL_EVENT_TIME, AST_EVENT_IE_PLTYPE_UINT, i_tvsec,
+ AST_EVENT_IE_CEL_EVENT_TIME_USEC, AST_EVENT_IE_PLTYPE_UINT, i_tvusec,
+ AST_EVENT_IE_CEL_USEREVENT_NAME, AST_EVENT_IE_PLTYPE_STR, e_udef,
+ AST_EVENT_IE_CEL_CIDNAME, AST_EVENT_IE_PLTYPE_STR, e_cid_name,
+ AST_EVENT_IE_CEL_CIDNUM, AST_EVENT_IE_PLTYPE_STR, e_cid_num,
+ AST_EVENT_IE_CEL_CIDANI, AST_EVENT_IE_PLTYPE_STR, e_cid_ani,
+ AST_EVENT_IE_CEL_CIDRDNIS, AST_EVENT_IE_PLTYPE_STR, e_cid_rdnis,
+ AST_EVENT_IE_CEL_CIDDNID, AST_EVENT_IE_PLTYPE_STR, e_cid_dnid,
+ AST_EVENT_IE_CEL_EXTEN, AST_EVENT_IE_PLTYPE_STR, e_exten,
+ AST_EVENT_IE_CEL_CONTEXT, AST_EVENT_IE_PLTYPE_STR, e_context,
+ AST_EVENT_IE_CEL_CHANNAME, AST_EVENT_IE_PLTYPE_STR, e_name,
+ AST_EVENT_IE_CEL_APPNAME, AST_EVENT_IE_PLTYPE_STR, e_appl,
+ AST_EVENT_IE_CEL_APPDATA, AST_EVENT_IE_PLTYPE_STR, e_appdata,
+ AST_EVENT_IE_CEL_AMAFLAGS, AST_EVENT_IE_PLTYPE_UINT, i_ama,
+ AST_EVENT_IE_CEL_ACCTCODE, AST_EVENT_IE_PLTYPE_STR, e_acctcode,
+ AST_EVENT_IE_CEL_PEERACCT, AST_EVENT_IE_PLTYPE_STR, e_peeracct,
+ AST_EVENT_IE_CEL_UNIQUEID, AST_EVENT_IE_PLTYPE_STR, e_uniqueid,
+ AST_EVENT_IE_CEL_LINKEDID, AST_EVENT_IE_PLTYPE_STR, e_linkedid,
+ AST_EVENT_IE_CEL_USERFIELD, AST_EVENT_IE_PLTYPE_STR, e_userfield,
+ AST_EVENT_IE_CEL_EXTRA, AST_EVENT_IE_PLTYPE_STR, e_extra,
+ AST_EVENT_IE_CEL_PEER, AST_EVENT_IE_PLTYPE_STR, e_peername,
+ AST_EVENT_IE_END);
+ if (!ev) {
+ ast_log(LOG_NOTICE,"NULL event returned\n");
+ return;
+ }
+ /* now, directly call the handler in the cel2cdr.c file */
+ cel2cdr_handle_event(ev, NULL); /* userdata, anyone?? */
+ }
+ } else {
+ printf("Couldn't open %s for read!\n", filename);
+ exit(11);
+ }
+ }
+ }
+}
Propchange: team/murf/cel2cdr/utils/csv2ev.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/murf/cel2cdr/utils/csv2ev.c
------------------------------------------------------------------------------
svn:keywords = Author Id Date Revision
Propchange: team/murf/cel2cdr/utils/csv2ev.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list