[Freeswitch-svn] [commit] r2077 - in freeswitch/trunk: . src/mod/event_handlers/mod_cdr w32/vsnet

Freeswitch SVN mikej at freeswitch.org
Mon Jul 24 11:19:05 EDT 2006


Author: mikej
Date: Mon Jul 24 11:19:05 2006
New Revision: 2077

Added:
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/Makefile
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/README
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/basecdr.cpp
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/basecdr.h
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/baseregistry.cpp
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/baseregistry.h
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/cdrcontainer.cpp
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/cdrcontainer.h
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/csvcdr.cpp
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/csvcdr.h
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/mod_cdr.cpp
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/mod_cdr.vcproj
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/mysqlcdr.cpp
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/mysqlcdr.h
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/pddcdr.cpp
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/pddcdr.h
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/schema-update.mysql
   freeswitch/trunk/src/mod/event_handlers/mod_cdr/schema.sql
Modified:
   freeswitch/trunk/AUTHORS
   freeswitch/trunk/w32/vsnet/Freeswitch.sln

Log:
Initial merge of mod_cdr.  Big thanks to Yossi Neiman for this huge contribution.  Please note that this is still somewhat a work in progress, but it works.

Modified: freeswitch/trunk/AUTHORS
==============================================================================
--- freeswitch/trunk/AUTHORS	(original)
+++ freeswitch/trunk/AUTHORS	Mon Jul 24 11:19:05 2006
@@ -22,6 +22,7 @@
  Michal "cypromis" Bielicki (michal.bielicki  AT halo2.pl) - Solaris porting, and autotools enhancements.
  James Martelletti <james at nerdc0re.com> - All around cool guy (mod_syslog)
  Johny Kadarisman <jkr888 at gmail.com>
+ Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>  -  implementation of mod_cdr (perldd, mysql, csv)
  
 A big THANK YOU goes to:
 

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/Makefile
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/Makefile	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,23 @@
+LDFLAGS += -I/usr/include/mysql -L/usr/lib64/mysql -lmysqlclient -lz -lcrypt -lnsl -lm -lssl -lcrypto
+CFLAGS += -I/usr/include/mysql -L/usr/lib64/mysql 
+CPPCC = g++
+OBJS=cdrcontainer.o basecdr.o baseregistry.o mysqlcdr.o pddcdr.o
+
+
+all:	depends $(OBJS) $(MODNAME).$(DYNAMIC_LIB_EXTEN)
+
+depends:
+
+$(MODNAME).$(DYNAMIC_LIB_EXTEN): $(OBJS) $(MODNAME).cpp
+	$(CPPCC) $(CFLAGS) -fPIC -c $(MODNAME).cpp -o $(MODNAME).o 
+	$(CPPCC) $(SOLINK) -o $(MODNAME).$(DYNAMIC_LIB_EXTEN)  $(MODNAME).o $(OBJS) $(LDFLAGS)
+
+
+%.o:  %.cpp
+	$(CPPCC) -Wall -Werror -fPIC $(CFLAGS) -c -o $@ $<
+
+clean:
+	rm -fr *.$(DYNAMIC_LIB_EXTEN) *.o *~
+
+install:
+	cp -f $(MODNAME).$(DYNAMIC_LIB_EXTEN) $(PREFIX)/mod

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/README
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/README	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,96 @@
+/*
+* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+*
+* Copyright 2006, Author: Yossi Neiman, president of Cartis Solutions, Inc. 
+* <freeswitch AT cartissolutions.com>
+*
+* Description: We don't need any documentation, do we?
+*
+* Version: MPL 1.1
+* The contents of this file are subject to the Mozilla Public License Version
+* 1.1 (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+* http://www.mozilla.org/MPL/
+*
+* Software distributed under the License is distributed on an "AS IS" basis,
+* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+* for the specific language governing rights and limitations under the
+* License
+*
+* The Core API is the FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application by
+* Anthony Minnesale II <anthmct at yahoo.com>
+*
+* README
+*
+*/
+
+mod_cdr has been written in C++ using class inheritence and virtual methods, and registers all classes that
+have been built in at load time.  It then calls up the connect() method on each particular object and if successful at initializing the object, it adds it to a data structure that contains 1 instance of every sucessfully configured and connected object.  This means that at any time after loading, it will only try to create objects that are functional, skipping any that are built in but are not desired for use at the current time.
+
+In order to use mod_cdr, you must uncomment this line in the freeswitch.xml configuration file located in the conf directory:  <load module="mod_cdr"/> in the <modules> section.  Then below this section, you need to uncomment this section <configuration name="mod_cdr.conf" description="CDR Configuration"> and input the per class configurations.  All class specific configurations go within this parent section as a subsection.
+
+There are currently the following types of loggers:
+
+Class: 		CsvCDR, located in csvcdr.h and csvcdr.cpp
+Description:	This is the standard CSV output class.  It has a default list of CDR elements that it always
+		logs, and the user can specify channel variables to be logged in a fixed order (chanvars_fixed) starting after the last default value to be logged.  Additionally, the user can specify additional channel variables to be logged after the fixed order channel variables as key=value pairs.
+Configuration:	Section name: <csvcdr>
+		<param name="path" value=""/>  value is the location to put the files (required)         <param name="size_limit" value=""/> value is the size limit of the output file, default value of 10MB (optional)
+		<param name="chanvars_fixed" value=""/> value is a comma separated list of fixed channel variables to log.  This cannot be a wildcard (*).  (optional)
+		<param name="chanvars_supp" value=""/>  value is a comma separated list of supplemental channel variables to log.  It can be a wildcard (*).  (optional)
+		<param name="repeat_fixed_in_supp" value=""/> value is a 0 for no, 1 for yes, and is for the case that you might want any fixed channel variables to be repeated in the supplemental list.
+		
+Class:		PddCDR, located in pddcdr.h and pddcdr.cpp
+Description:	This is the Perl Data Dumper output class.  It writes each record to an individual text file
+		containing all the information.  It does not distinguish between fixed and supplemental channel variables.  If you are running freeswitch in a high volume environment, it is important to note that these individual files are small,  often times between 750 and 1500 bytes.  It is therefore recommended to use a partition with small cluster sizes or (on systems supporting) on reiserfs or reiser4 filesystems which are both excellent handlers of large numbers of small files.
+Configuration:	Section name: <pddcdr>
+		<param name="path" value=""/>  value is the path where you want the output files (required)
+		<param name="chanvars" value=""/> value is a comma separated list of channel variables to log.  It can accept a wildcard (*) (optional)
+
+Class:		MysqlCDR, located in mysqlcdr.h and mysqlcdr.cpp
+Description:	This class logs the call detail record to a MySQL 4.1.x or greater database using prepared
+		statements.  This class is a little more complex than the prior two in that the fixed channel variables are treated as additional columns on the main freeswitchcdr database table for improved normalization of the database.  As such, you need to specify the format of each fixed channel variable as well.  If you do not specify, it will default to a varchar column type, and will not execute if the table schema does not match.  Therefore it is very important to make sure that any fixed channel variables you log exist as columns on the table.  The supplemental channel variables are stored in a separate table using a key / value pair linking to the callid of the call.
+Configuration:	Section: <mysqlcdr>
+		<param name="hostname" value=""/> value is the hostname or IP of the MySQL server (required)
+		<param name="username" value=""/> value is the username to connect to the MySQL server with (required)
+		<param name="password" value=""/> value is the password to use to authenticate to the MySQL server with (required)
+		<param name="dbname" value=""/> value is the name of the database to connect to (required)
+		<param name="chanvars_fixed" value=""/> Is a comma separated list of key=type pairs.  Types are x for decimal, s for string (varchar), d for double, i for integer, t for tiny.  If no type is provided, it defaults that column to string (varchar).  It cannot accept wildcards (*).  (optional)
+		<param name="chanvars_supp" value=""/> value is a comma separated list of supplemental channel variables to log.  Can be a wildcard (*) (optional)
+		<param name="chanvars_supp_repeat_fixed" value=""/> value is 0 for no, 1 for yes, and determines whether or not to repeat any of the fixed channel variables as key / value pairs in the chanvars table.
+
+FAQ:
+
+Q: Why C++?
+A: Why not?  It works well in this design.
+
+Q: Why is there a distinction between fixed and supplemental channel variables?
+A: There is a distinction so that a level of uniformity can be maintain on those loggers that require uniformity.  For example, if you expect that channel variable FOO will always been at a specific location on a CSV row, then it is required that it be a fixed channel variable.  The fixed means that it is a fixed position, and needs to be logged even if it is blank.  Supplemental channel variables, on the other hand, are more dynamic, and will only log those channel variables that actually exist on that given leg of the call.  That means that if you supply a wildcard, it will simply iterate all the channel variables.  If you do not want to repeat the fixed channel variables in the supplemental channel variables, it will then remove the fixed channel variables from the data structure holding the supplemental channel variables even before the process_record() method is called up.
+
+Q: What would an example configuration look like?
+A: Here is an excerpt from the freeswitch XML configuration file:
+
+	<configuration name="mod_cdr.conf" description="CDR Configuration">
+		<pddcdr>
+			<param name="path" value="/work/temp/pddcdr"/>
+			<param name="chanvars" value="username,accountcode"/>
+			<param name="chanvars_fixed" value="*"/>
+		</pddcdr>
+		<csvcdr>
+			<param name="path" value="/work/temp/csvcdr"/>
+			<param name="size_limit" value="25"/>
+			<param name="chanvars_fixed" value="username"/>
+			<param name="chanvars_supp" value="*"/>
+			<param name="repeat_fixed_in_supp" value="0"/>
+		</csvcdr>
+		<mysqlcdr>
+			<param name="hostname" value="10.0.0.1"/>
+			<param name="username" value="test"/>
+			<param name="password" value="test"/>
+			<param name="dbname" value="testing"/>
+			<param name="chanvars_fixed" value="username=s,The_Kow=t"/>
+			<!-- This previous line logs username as a varchar, and The_Kow as a tiny -->
+			<param name="chanvars_supp" value="*"/>
+			<param name="chanvars_supp_repeat_fixed" value="0"/>
+		</mysqlcdr>
+	</configuration>

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/basecdr.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/basecdr.cpp	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,358 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ source file describes the BaseCDR class that all other CDR classes inherit from.
+ * It handles the bulk of the processing of data from the switch_channel_t objects.
+ *
+ * basecdr.cpp
+ *
+ */
+
+#include "basecdr.h"
+#include <iostream>
+#include <string>
+#include <cstring>
+#include <switch.h>
+
+BaseCDR::BaseCDR()
+{
+	callstartdate = 0;
+	callanswerdate = 0;
+	callenddate = 0;
+	strncpy(clid,"Unknown",7);
+	strncpy(src,"-1",2);
+	strncpy(dst,"-1",2);
+	strncpy(srcchannel,"-1",2);
+	strncpy(dstchannel,"-1",2);
+	strncpy(lastapp,"-1",2);
+	billusec = 0;
+	disposition=0;
+	amaflags = 0;
+	errorstate = 0;
+}
+
+BaseCDR::BaseCDR(switch_mod_cdr_newchannel_t *newchannel)
+{
+	if(newchannel != 0)
+	{
+		memset(clid,0,80);
+		memset(dialplan,0,80);
+		memset(myuuid,0,37);
+		memset(destuuid,0,37);
+		memset(dialplan,0,80);
+		memset(&hangupcause,0,sizeof(hangupcause));
+		hangupcause_text = 0;
+		memset(src,0,80);
+		memset(dst,0,80);
+		memset(srcchannel,0,80);
+		memset(dstchannel,0,80);
+		memset(network_addr,0,40);
+		memset(ani,0,80);
+		memset(ani2,0,80);
+		memset(lastapp,0,80);
+		memset(lastdata,0,255);
+
+		coresession = newchannel->session;
+		callstartdate= newchannel->timetable->created;
+		callanswerdate = newchannel->timetable->answered;
+		callenddate = newchannel->timetable->hungup;
+	
+		if(newchannel->callerprofile->caller_id_name != 0)
+		{
+			strncpy(clid,newchannel->callerprofile->caller_id_name,strlen(newchannel->callerprofile->caller_id_name));
+			strncat(clid," ",1);
+			if(newchannel->callerprofile->caller_id_number != 0 )
+				strncat(clid,newchannel->callerprofile->caller_id_number,strlen(clid)+strlen(newchannel->callerprofile->caller_id_number));
+		}
+		
+		// Get the ANI information if it's set
+		if(newchannel->callerprofile->ani != 0)
+			strncpy(ani,newchannel->callerprofile->ani,strlen(newchannel->callerprofile->ani));
+		if(newchannel->callerprofile->ani2 != 0)
+			strncpy(ani2,newchannel->callerprofile->ani2,strlen(newchannel->callerprofile->ani2));
+	
+		if(newchannel->callerprofile->dialplan != 0)
+			strncpy(dialplan,newchannel->callerprofile->dialplan,strlen(newchannel->callerprofile->dialplan));
+	
+		if(newchannel->callerprofile->network_addr != 0)
+			strncpy(network_addr,newchannel->callerprofile->network_addr,strlen(newchannel->callerprofile->network_addr));
+		
+		switch_console_printf(SWITCH_CHANNEL_LOG, "BaseCDR::BaseCDR(switch_mod_cdr_newchannel*) - Channel caller_profile loaded.\n");
+		
+		originated = newchannel->originate;
+	
+		if(newchannel->originateprofile->uuid != 0)
+			strncpy(destuuid,newchannel->originateprofile->uuid,strlen(newchannel->originateprofile->uuid));
+	
+		// We still need to check if this is originated or not
+		if(originated == 0)
+		{
+			if(newchannel->callerprofile->destination_number != 0)
+				strncpy(src,newchannel->callerprofile->destination_number,strlen(newchannel->callerprofile->destination_number));
+			if(newchannel->callerprofile->caller_id_number != 0)
+				strncpy(dst,newchannel->callerprofile->caller_id_number,strlen(newchannel->callerprofile->caller_id_number));
+			if(newchannel->originateprofile->chan_name != 0)
+				strncpy(dstchannel,newchannel->originateprofile->chan_name,strlen(newchannel->originateprofile->chan_name));
+		}
+		else
+		{
+			if(newchannel->callerprofile->caller_id_number != 0)
+				strncpy(src,newchannel->callerprofile->caller_id_number,strlen(newchannel->callerprofile->caller_id_number));
+			if(newchannel->callerprofile->destination_number != 0)
+				strncpy(dst,newchannel->callerprofile->destination_number,strlen(newchannel->callerprofile->destination_number));
+			if(newchannel->originateprofile->chan_name != 0)
+				strncpy(dstchannel,newchannel->originateprofile->chan_name,strlen(newchannel->originateprofile->chan_name));
+		}
+		
+		strncpy(myuuid,newchannel->callerprofile->uuid,strlen(newchannel->callerprofile->uuid));
+		strncpy(srcchannel,newchannel->callerprofile->chan_name,strlen(newchannel->callerprofile->chan_name));
+		
+		if(switch_channel_test_flag(newchannel->channel,CF_ANSWERED))
+		{
+			disposition=1;
+			billusec = newchannel->timetable->hungup - newchannel->timetable->answered;
+		}
+		else
+		{
+			disposition=0;
+			billusec = 0;
+		}
+		
+		// What was the hangup cause?
+		hangupcause = switch_channel_get_cause(newchannel->channel);
+		hangupcause_text = switch_channel_cause2str(hangupcause);
+	
+		switch_console_printf(SWITCH_CHANNEL_LOG, "BaseCDR::BaseCDR(switch_mod_cdr_newchannel*) - Call state & length calculated.\n");
+		
+		if(newchannel->callerextension != 0)
+			if(newchannel->callerextension->last_application != 0)
+			{
+				if(newchannel->callerextension->last_application->application_name != 0)
+					strncpy(lastapp,newchannel->callerextension->last_application->application_name,strlen(newchannel->callerextension->last_application->application_name));
+				if(newchannel->callerextension->last_application->application_data != 0)
+					strncpy(lastdata,newchannel->callerextension->last_application->application_data,strlen(newchannel->callerextension->last_application->application_data));
+			}
+		
+		amaflags=0;
+		
+		switch_console_printf(SWITCH_CHANNEL_LOG, "BaseCDR::BaseCDR(switch_mod_cdr_newchannel*) - Processing completed.\n");
+	}
+}
+
+BaseCDR::~BaseCDR()
+{
+
+}
+
+/* bool fixed is for checking if this is the fixed or supplemental list */
+void BaseCDR::parse_channel_variables_xconfig(std::string& unparsed,std::list<std::string>& chanvarlist,bool fixed)
+{
+	std::string tempstring;
+	for(std::string::size_type i = 0, j = 0; j != std::string::npos; )
+	{
+		j = unparsed.find(',',i);
+		if(j > 0)
+		{
+			tempstring = unparsed.substr(i,(j-i));
+			chanvarlist.push_back(tempstring);
+			i =j+1;
+		}
+		else
+		{
+			tempstring = unparsed.substr(i);
+			chanvarlist.push_back(tempstring);
+		}
+	}
+	
+	// Now we need to clean up in case somebody put in a '*' in the chanvars fixed list
+	std::list<std::string>::iterator iBeg,iItr,iEnd;
+	iBeg = chanvarlist.begin();
+	iEnd = chanvarlist.end();
+	bool exitcode = 1;
+	for(iItr = chanvarlist.begin(); iItr != iEnd && exitcode ; )
+	{
+		if(iItr->find('*',0) != std::string::npos)
+		{
+			if(fixed)
+			{
+				switch_console_printf(SWITCH_CHANNEL_LOG,"Wildcards are not allow in the fixed chanvars list.  Item removed.\n");
+				iItr = chanvarlist.erase(iItr);
+			}
+			else
+			{
+				if(chanvarlist.size() > 1) 
+				chanvarlist.clear();
+				std::string all = "*";
+				chanvarlist.push_back(all);
+				exitcode = 0;
+			}
+		}
+		else
+			iItr++;
+	}
+}
+
+void BaseCDR::parse_channel_variables_xconfig(std::string& unparsed,std::list<std::string>& chanvarlist,std::vector<switch_mod_cdr_sql_types_t>& chanvars_fixed_types)
+{
+	bool fixed = 1;
+	std::string tempstring, tempstring2;
+	switch_mod_cdr_sql_types_t sql_type;
+	parse_channel_variables_xconfig(unparsed,chanvarlist,fixed);
+	std::list<std::string> tempchanvarlist; // = chanvarlist;
+	std::list<std::string>::iterator iEnd, iItr;
+	
+	for(iItr = chanvarlist.begin(), iEnd = chanvarlist.end() ; iItr != iEnd ; iItr++)
+	{
+		sql_type = CDR_STRING;
+		std::string::size_type i = 0, j = 0;
+		j = iItr->find('=',i);
+		if(j > 0 )
+		{
+			tempstring = iItr->substr(i,(j-i));
+			i =j+1;
+			tempstring2 = iItr->substr(i);
+			if(tempstring2.size() == 1)
+			{
+				switch(tempstring2[0])
+				{
+					case 'I':
+					case 'i':
+						sql_type = CDR_INTEGER;
+						break;
+					case 'S':
+					case 's':
+						sql_type = CDR_STRING;
+						break;
+					case 'D':
+					case 'd':
+						sql_type = CDR_DOUBLE;
+						break;
+					case 'T':
+					case 't':
+						sql_type = CDR_TINY;
+						break;
+					default:
+						switch_console_printf(SWITCH_CHANNEL_LOG,"Valid fixed channel variable types are x (decimal), d (double), i (integer), t (tiny), s (string).  You tried to give a type of %s to chanvar %s.\nReverting this chanvar type to a string type.\n",tempstring2.c_str(),tempstring.c_str());
+						sql_type = CDR_STRING;
+				}
+			}
+			else
+			{
+				switch_console_printf(SWITCH_CHANNEL_LOG,"Valid fixed channel variable types are x (decimal), d (double), i (integer), t (tiny), s (string).  You tried to give a type of %s to chanvar %s.\nReverting this chanvar type to a string type.\n",tempstring2.c_str(),tempstring.c_str());
+				sql_type = CDR_STRING;
+			}
+		}
+		else
+		{
+			switch_console_printf(SWITCH_CHANNEL_LOG,"No parameter set, for channel variable %s, using default type of string.\n",iItr->c_str());
+			sql_type = CDR_STRING;
+			tempstring = *iItr;
+		}
+			
+		tempchanvarlist.push_back(tempstring);
+		chanvars_fixed_types.push_back(sql_type);
+	}
+	
+	chanvarlist.clear();
+	chanvarlist = tempchanvarlist;
+}
+
+// This is for processing the fixed channel variables
+void BaseCDR::process_channel_variables(const std::list<std::string>& stringlist,switch_channel_t *channel)
+{
+	std::list<std::string>::const_iterator iItr,iEnd;
+	iEnd = stringlist.end();
+		
+	for(iItr = stringlist.begin(); iItr != iEnd; iItr++)
+	{
+		std::vector<char> tempstringvector(iItr->begin(), iItr->end());
+		tempstringvector.push_back('\0');
+		char* tempstring= &tempstringvector[0];
+
+		char *tempvariable;
+		tempvariable = switch_channel_get_variable(channel,tempstring);
+		
+		
+		std::pair<std::string,std::string> temppair;
+		temppair.first = *iItr;
+			
+		if(tempvariable != 0)
+			temppair.second = tempvariable;
+		
+		chanvars_fixed.push_back(temppair);
+	}	
+}
+
+// This one is for processing of supplemental chanvars
+void BaseCDR::process_channel_variables(const std::list<std::string>& stringlist, const std::list<std::string>& fixedlist, switch_channel_t *channel,bool repeat)
+{
+	if(stringlist.front() == "*")
+	{
+		switch_hash_index_t *hi;
+		void *val;
+		const void *var;
+		switch_memory_pool_t *sessionpool;
+		sessionpool = switch_core_session_get_pool(coresession);
+		for (hi = switch_channel_variable_first(channel,sessionpool); hi; hi = switch_hash_next(hi)) 
+		{
+			switch_hash_this(hi, &var, 0, &val);
+			std::string tempstring_first, tempstring_second;
+			tempstring_first = (char *) var;
+			tempstring_second = (char *) val;
+			chanvars_supp[tempstring_first] = tempstring_second;
+		}
+	}
+	else
+	{
+		std::list<std::string>::const_iterator iItr,iEnd;
+		iEnd = stringlist.end();
+			
+		for(iItr = stringlist.begin(); iItr != iEnd; iItr++)
+		{
+			std::vector<char> tempstringvector(iItr->begin(), iItr->end());
+			tempstringvector.push_back('\0');
+			char* tempstring= &tempstringvector[0];
+
+			char *tempvariable;
+			tempvariable = switch_channel_get_variable(channel,tempstring);
+			if(tempvariable != 0)
+				chanvars_supp[*iItr] = tempvariable;
+		}
+	}
+	
+	if(!repeat)
+	{
+		std::map<std::string,std::string>::iterator MapItr;
+		std::list<std::string>::const_iterator iItr,iEnd;
+		for(iItr = fixedlist.begin(), iEnd = fixedlist.end(); iItr != iEnd; iItr++)
+		{
+			MapItr = chanvars_supp.find(*iItr);
+			if(MapItr != chanvars_supp.end() )
+				chanvars_supp.erase(MapItr);
+		}
+	}
+}

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/basecdr.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/basecdr.h	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,107 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This header describes the switch_mod_cdr_newchannel_t struct, the BaseCDR base class that all
+ * CDR loggers will inherit from, and the switch_mod_cdr_sql_types_t enum for use with the SQL type loggers
+ * (i.e. MySQL).  This is part of the mod_cdr module for Freeswitch by Anthony Minnesale and friends.
+ *
+ * basecdr.h
+ *
+ */
+
+#ifndef BASECDR
+#define BASECDR
+
+#ifdef __cplusplus
+#include <vector>
+#include <list>
+#include <vector>
+#include <map>
+#include <switch.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+struct switch_mod_cdr_newchannel_t 
+{
+	switch_core_session_t *session;
+	switch_channel_t *channel;
+	switch_channel_timetable_t *timetable;
+	switch_caller_extension_t *callerextension;
+	switch_caller_profile_t *callerprofile;
+	switch_caller_profile_t *originateprofile;
+	bool originate;
+};
+
+enum switch_mod_cdr_sql_types_t { CDR_INTEGER,CDR_STRING,CDR_DECIMAL,CDR_DOUBLE,CDR_TINY };
+
+class BaseCDR {
+	public:
+		BaseCDR();
+		virtual ~BaseCDR();
+		BaseCDR(switch_mod_cdr_newchannel_t *newchannel);
+		virtual void connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param) = 0;
+		virtual void disconnect() = 0;
+		virtual bool process_record() = 0;
+		virtual bool is_activated() = 0;
+		virtual void tempdump_record() = 0;
+		virtual void reread_tempdumped_records() = 0;
+	protected:
+		void parse_channel_variables_xconfig(std::string& unparsed,std::list<std::string>& chanvarslist,bool fixed);
+		void parse_channel_variables_xconfig(std::string& unparsed,std::list<std::string>& chanvarslist,std::vector<switch_mod_cdr_sql_types_t>& chanvars_fixed_types);  // Typically used for SQL types
+		void process_channel_variables(const std::list<std::string>& stringlist,const std::list<std::string>& fixedlist,switch_channel_t *channel,bool repeat = 1); //This is used for supplemental chanvars
+		void process_channel_variables(const std::list<std::string>& stringlist,switch_channel_t *channel); // This is used for fixed chanvars
+		switch_time_t callstartdate;
+		switch_time_t callanswerdate;
+		switch_time_t callenddate;
+		switch_call_cause_t hangupcause;
+		char *hangupcause_text;
+		char clid[80];
+		bool originated;  // Did they originate this call?
+		char dialplan[80];
+		char myuuid[37]; // 36 + 1 to hold \0
+		char destuuid[37];
+		char src[80];
+		char dst[80];
+		char srcchannel[80];
+		char dstchannel[80];
+		char ani[80];
+		char ani2[80];
+		char network_addr[40];
+		char lastapp[80];
+		char lastdata[255]; 
+		switch_time_t billusec; // Yes, you heard me, we're measuring in microseconds
+		int disposition; // Currently 0 = Busy/Unanswered, 1 = Answered
+		int amaflags;
+		switch_core_session_t *coresession;
+		std::list<std::pair<std::string,std::string> > chanvars_fixed;
+		std::map<std::string,std::string> chanvars_supp;
+		bool errorstate; // True if there is an error writing the log
+};
+
+#endif
+#endif

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/baseregistry.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/baseregistry.cpp	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,81 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ source describes the BaseRegistry and BaseRegistration classes that implement
+ * the factory routine with the aid of the templated base_factory() function.
+ *
+ * baseregistry.cpp
+ *
+ */
+
+#include "baseregistry.h"
+
+BaseRegistry& BaseRegistry::get()
+{
+	static BaseRegistry instance;
+	return instance;
+}
+
+void BaseRegistry::add(basecdr_creator creator)
+{
+	m_bases.push_back(creator);
+}
+
+BaseRegistry::iterator BaseRegistry::begin()
+{
+	return m_bases.begin();
+}
+
+BaseRegistry::iterator BaseRegistry::end()
+{ 
+	return m_bases.end(); 
+}
+
+void BaseRegistry::reset_active()
+{
+	active_bases.clear();
+}
+
+void BaseRegistry::add_active(iterator tempobject)
+{
+	active_bases.push_back(*tempobject);
+}
+
+BaseRegistry::iterator BaseRegistry::active_begin()
+{
+	return active_bases.begin();
+}
+
+BaseRegistry::iterator BaseRegistry::active_end()
+{
+	return active_bases.end();
+}
+
+BaseRegistration::BaseRegistration(basecdr_creator creator)
+{
+	BaseRegistry::get().add(creator);
+}

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/baseregistry.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/baseregistry.h	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,78 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: BaseRegistry and BaseRegistration classes and AUTO_REGISTER_BASECDR macro provided in part by David 
+ * Terrell from his blog posting http://meat.net/2006/03/cpp-runtime-class-registration/  Much thanks to him 
+ * for his help.
+ *
+ * baseregistry.h
+ *
+ */
+
+#include "basecdr.h"
+#include <iostream>
+
+#ifndef BASECDRREGISTRY
+#define BASECDRREGISTRY
+
+#ifdef __cplusplus
+#include <vector>
+
+template<class T> BaseCDR* basecdr_factory(switch_mod_cdr_newchannel_t *newchannel)
+{
+	return new T(newchannel);
+}
+
+typedef BaseCDR* (*basecdr_creator)(switch_mod_cdr_newchannel_t *newchannel);
+
+class BaseRegistry
+{
+	private:
+		std::vector<basecdr_creator> m_bases; // Stores all modules
+		std::vector<basecdr_creator> active_bases; // Stores only active modules
+	public:
+		typedef std::vector<basecdr_creator>::iterator iterator;
+		static BaseRegistry& get();
+		void add(basecdr_creator);
+		void reset_active(); // Clears the active vector for reloading of configuration.
+		void add_active(iterator);
+		iterator begin();
+		iterator end();
+		iterator active_begin();
+		iterator active_end();
+};
+
+class BaseRegistration
+{
+	public:
+		BaseRegistration(basecdr_creator);
+};
+
+#define AUTO_REGISTER_BASECDR(basecdr) BaseRegistration _basecdr_registration_ ## basecdr(&basecdr_factory<basecdr>);
+
+#endif // ifdef __cplusplus
+#endif

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/cdrcontainer.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/cdrcontainer.cpp	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,165 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ source file describes the CDRContainer singleton object used by mod_cdr to control
+ * the creation, processing, and destruction of various CDR logger objects.
+ *
+ * cdrcontainer.cpp
+ *
+ */
+
+#include "cdrcontainer.h"
+#include "baseregistry.h"
+
+CDRContainer::CDRContainer()
+{
+
+}
+
+CDRContainer::CDRContainer(switch_memory_pool_t *module_pool)
+{
+	// Create the APR threadsafe queue, though I don't know if this is the current memory pool.
+	switch_queue_create(&cdrqueue,5224288, module_pool);
+	
+	char *configfile = "mod_cdr.conf";
+	switch_xml_t cfg, xml, settings, param;
+	
+	switch_mod_cdr_newchannel_t *newchannel; // = new switch_mod_cdr_newchannel_t;
+	newchannel = 0;
+	
+	if (!(xml = switch_xml_open_cfg(configfile, &cfg, NULL))) 
+		switch_console_printf(SWITCH_CHANNEL_LOG,"open of %s failed\n", configfile);
+	else
+	{	
+		BaseRegistry& registry(BaseRegistry::get());
+		for(BaseRegistry::iterator it = registry.begin(); it != registry.end(); ++it)
+		{
+			basecdr_creator func = *it;
+			BaseCDR* _ptr = func(newchannel);
+			std::auto_ptr<BaseCDR> ptr(_ptr);
+			ptr->connect(cfg,xml,settings,param);
+			
+			if(ptr->is_activated())
+				registry.add_active(it);
+		}
+	}
+
+	switch_xml_free(xml);
+}
+
+CDRContainer::~CDRContainer()
+{
+	if(switch_queue_size(cdrqueue) > 0)
+		process_records();
+	
+	switch_mod_cdr_newchannel_t *newchannel; //= new switch_mod_cdr_newchannel_t;
+	newchannel = 0;
+	
+	BaseRegistry& registry(BaseRegistry::get());
+	for(BaseRegistry::iterator it = registry.active_begin(); it != registry.active_end(); ++it)
+	{
+		basecdr_creator func = *it;
+		BaseCDR* _ptr = func(newchannel);
+		std::auto_ptr<BaseCDR> ptr(_ptr);
+		ptr->disconnect();
+	}
+		
+	switch_console_printf(SWITCH_CHANNEL_LOG,"mod_cdr shutdown gracefully.");
+}
+
+void CDRContainer::add_cdr(switch_core_session_t *session)
+{
+	switch_mod_cdr_newchannel_t *newchannel = new switch_mod_cdr_newchannel_t;
+	memset(newchannel,0,sizeof(*newchannel));
+	
+	newchannel->channel = switch_core_session_get_channel(session);
+	assert(newchannel->channel != 0);
+
+	newchannel->session = session;
+	newchannel->timetable = switch_channel_get_timetable(newchannel->channel);
+	newchannel->callerextension = switch_channel_get_caller_extension(newchannel->channel);
+	newchannel->callerprofile = switch_channel_get_caller_profile(newchannel->channel);
+	newchannel->originateprofile = switch_channel_get_originator_caller_profile(newchannel->channel);	
+	
+	BaseRegistry& registry(BaseRegistry::get());
+	for(BaseRegistry::iterator it = registry.active_begin(); it != registry.active_end(); ++it)
+	{
+		/* 
+		   First time it might be originator profile, or originatee.  Second and 
+		   after is always going to be originatee profile.
+		*/
+		
+		basecdr_creator func = *it;
+		
+		if(newchannel->originateprofile != 0 )
+		{
+			BaseCDR* newloggerobject = func(newchannel);
+			switch_console_printf(SWITCH_CHANNEL_LOG,"Adding a new logger object to the queue.\n");
+			switch_queue_push(cdrqueue,newloggerobject);
+			
+			if(newchannel->timetable->next != 0)
+			{
+				newchannel->originateprofile = switch_channel_get_originatee_caller_profile(newchannel->channel);
+				newchannel->originate = 1;
+			}	
+		}
+		else
+		{
+			newchannel->originateprofile = switch_channel_get_originatee_caller_profile(newchannel->channel);
+			newchannel->originate = 1;
+			
+			BaseCDR* newloggerobject = func(newchannel);
+			switch_console_printf(SWITCH_CHANNEL_LOG,"Adding a new logger object to the queue.\n");
+			switch_queue_push(cdrqueue,newloggerobject);
+		}
+		
+		while (newchannel->timetable->next != 0 && newchannel->callerextension->next != 0 && newchannel->callerprofile->next != 0 && newchannel->originateprofile->next != 0 ) 
+		{			
+			newchannel->timetable = newchannel->timetable->next;
+			newchannel->callerprofile = newchannel->callerprofile->next;
+			newchannel->callerextension = newchannel->callerextension->next;
+			newchannel->originateprofile = newchannel->originateprofile->next;
+			
+			BaseCDR* newloggerobject = func(newchannel);
+			switch_console_printf(SWITCH_CHANNEL_LOG,"Adding a new logger object to the queue.\n");
+			switch_queue_push(cdrqueue,newloggerobject);
+		}
+	}
+	
+	delete newchannel;
+}
+
+void CDRContainer::process_records()
+{
+		BaseCDR *tempnewloggerobject = 0, *newloggerobject = 0;
+		while(switch_queue_pop(cdrqueue,reinterpret_cast< void** > (&tempnewloggerobject))== SWITCH_STATUS_SUCCESS)
+		{
+			newloggerobject = tempnewloggerobject;
+			newloggerobject->process_record();
+			delete newloggerobject;
+		}
+}

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/cdrcontainer.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/cdrcontainer.h	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,71 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ header file describes the CDRContainer singleton object used by mod_cdr to control
+ * the creation, processing, and destruction of various CDR logger objects.
+ *
+ * cdrcontainer.h
+ *
+ */
+
+#ifndef CDRCONTAINER
+#define CDRCONTAINER
+
+#ifdef __cplusplus
+#include <cstring>
+#include <iostream>
+#endif
+#include "basecdr.h"
+#include <switch.h>
+
+/*
+The CDRContainer Class will serve as a central receptacle for all CDR methods.  CDRContainer::CDRContainer() will initialize the system, and CDRContainer::add_cdr() will add a new object of each CDR type to a queue for "later processing" by the other thread.
+CDRContainer::process_records() will iterate thru the queue and commit the records to the respective backends.
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+class CDRContainer {
+	public:
+		CDRContainer();
+		CDRContainer(switch_memory_pool_t *module_pool);
+		~CDRContainer();
+		void add_cdr(switch_core_session_t *session);
+		void process_records();
+	protected:
+	private:
+		switch_queue_t *cdrqueue;
+		std::string tempfilepath;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/csvcdr.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/csvcdr.cpp	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,286 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ source file describes the CsvCDR class that handles processing CDRs to a CSV format.
+ * This is the standard CSV module, and has a list of predefined variables to log out which can be
+ * added to, but never have the default ones removed.  If you want to use one that allows you to explicity
+ * set all data variables to be logged and in what order, then this is not the class you want to use, and
+ * one will be coming in the future to do just that.
+ *
+ * csvcdr.cpp
+ *
+ */
+
+#include <switch.h>
+#include "csvcdr.h"
+#include <string>
+
+
+CsvCDR::CsvCDR() : BaseCDR()
+{
+	memset(formattedcallstartdate,0,100);
+	memset(formattedcallanswerdate,0,100);
+	memset(formattedcallenddate,0,100);
+}
+
+CsvCDR::CsvCDR(switch_mod_cdr_newchannel_t *newchannel) : BaseCDR(newchannel)
+{
+	memset(formattedcallstartdate,0,100);
+	memset(formattedcallanswerdate,0,100);
+	memset(formattedcallenddate,0,100);
+	
+	if(newchannel != 0)
+	{
+		switch_time_exp_t tempcallstart, tempcallanswer, tempcallend;
+		memset(&tempcallstart,0,sizeof(tempcallstart));
+		memset(&tempcallanswer,0,sizeof(tempcallanswer));
+		memset(&tempcallend,0,sizeof(tempcallend));
+		switch_time_exp_lt(&tempcallstart, callstartdate);
+		switch_time_exp_lt(&tempcallanswer, callanswerdate);
+		switch_time_exp_lt(&tempcallend, callenddate);
+		
+		// Format the times
+		apr_size_t retsizecsd, retsizecad, retsizeced;  //csd == callstartdate, cad == callanswerdate, ced == callenddate, ceff == callenddate_forfile
+		char format[] = "%F %T";
+		switch_strftime(formattedcallstartdate,&retsizecsd,sizeof(formattedcallstartdate),format,&tempcallstart);
+		switch_strftime(formattedcallanswerdate,&retsizecad,sizeof(formattedcallanswerdate),format,&tempcallanswer);
+		switch_strftime(formattedcallenddate,&retsizeced,sizeof(formattedcallenddate),format,&tempcallend);
+
+		process_channel_variables(chanvars_fixed_list,newchannel->channel);
+		process_channel_variables(chanvars_supp_list,chanvars_fixed_list,newchannel->channel,repeat_fixed_in_supp);
+	}
+}
+
+CsvCDR::~CsvCDR()
+{
+
+}
+
+bool CsvCDR::activated=0;
+bool CsvCDR::logchanvars=0;
+bool CsvCDR::connectionstate=0;
+bool CsvCDR::repeat_fixed_in_supp=0;
+std::string CsvCDR::outputfile_path;
+std::ofstream CsvCDR::outputfile;
+std::ofstream::pos_type CsvCDR::filesize_limit = (10 * 1024 * 1024); // Default file size is 10MB
+std::list<std::string> CsvCDR::chanvars_fixed_list;
+std::list<std::string> CsvCDR::chanvars_supp_list;
+
+void CsvCDR::connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param)
+{
+	switch_console_printf(SWITCH_CHANNEL_LOG, "CsvCDR::connect() - Loading configuration file.\n");
+	activated = 0; // Set it as inactive initially
+	connectionstate = 0; // Initialize it to false to show that we aren't yet connected.
+	
+	if ((settings = switch_xml_child(cfg, "csvcdr"))) 
+	{
+		int count_config_params = 0;  // Need to make sure all params are set before we load
+		for (param = switch_xml_child(settings, "param"); param; param = param->next) 
+		{
+			char *var = (char *) switch_xml_attr_soft(param, "name");
+			char *val = (char *) switch_xml_attr_soft(param, "value");
+
+			if (!strcmp(var, "path"))
+			{
+				if(val != 0)
+					outputfile_path = val;
+				count_config_params++;
+			}
+			else if (!strcmp(var, "chanvars_supp")) 
+			{
+				if(val != 0)
+				{
+					std::string unparsed;
+					unparsed = val;
+					if(unparsed.size() > 0)
+					{
+						bool fixed = 0;
+						parse_channel_variables_xconfig(unparsed,chanvars_supp_list,fixed);
+						logchanvars=1;
+					}
+				}
+			}
+			else if (!strcmp(var, "chanvars_fixed"))
+			{
+				if(val != 0)
+				{
+					std::string unparsed;
+					unparsed = val;
+					if(unparsed.size() > 0)
+					{
+						bool fixed = 1;
+						parse_channel_variables_xconfig(unparsed,chanvars_fixed_list,fixed);
+						logchanvars=1;
+					}
+				}
+			}
+			else if (!strcmp(var, "repeat_fixed_in_supp"))
+			{
+				if(!strcmp(val,"1"))
+					repeat_fixed_in_supp = 1;
+				else if (!strcmp(val,"y") || !strcmp(val,"y"))
+					repeat_fixed_in_supp = 0;
+			}
+			else if (!strcmp(var, "size_limit"))
+			{
+				if(val != 0)
+				{
+					filesize_limit = atoi(val) * 1024 * 1024; // Value is in MB
+					std::cout << "File size limit from config file is " << filesize_limit << " byte(s)." << std::endl;
+				}
+			}
+		}
+		
+		if(count_config_params > 0)
+		{
+			open_file();
+			if(outputfile.good())
+			{
+				activated = 1;
+				switch_console_printf(SWITCH_CHANNEL_LOG,"CsvCDR activated, log rotation will occur at or after %d MB",(filesize_limit/1024/1024));
+			}
+		}
+		else
+			switch_console_printf(SWITCH_CHANNEL_LOG,"CsvCDR::connect(): You did not specify the minimum parameters for using this module.  You must specify at least a path to have the records logged to.\n");
+	}
+}
+
+void CsvCDR::check_file_size_and_open()
+{
+	// Test if the file has been opened or not
+	if(outputfile)
+	{
+		if(outputfile.tellp() > filesize_limit)
+			outputfile.close();
+	}
+	
+	if (!outputfile)
+	{
+		open_file();
+	}
+}
+
+void CsvCDR::open_file()
+{
+	switch_time_t now = switch_time_now();
+	switch_time_exp_t now_converted;
+	memset(&now_converted,0,sizeof(now_converted));
+		
+	switch_time_exp_lt(&now_converted,now);
+		
+	apr_size_t retsize;		
+	char format[] = "%F %T";
+	char formatteddate[100];
+	memset(formatteddate,0,100);
+	switch_strftime(formatteddate,&retsize,100,format,&now_converted);
+		
+	std::string filename = outputfile_path;
+	filename.append(SWITCH_PATH_SEPARATOR);
+	filename.append(formatteddate);
+	filename.append(".csv");
+	outputfile.clear();
+		
+	outputfile.open(filename.c_str(),std::ios_base::app|std::ios_base::binary);
+	if(outputfile.fail())
+	{
+		switch_console_printf(SWITCH_CHANNEL_LOG,"Could not open the CSV file %s .  CsvCDR logger will not be functional until this is resolved and a reload is issued.  Failbit is set to %d.\n",filename.c_str(),outputfile.fail());
+		activated = 0;
+	}
+	
+}
+
+bool CsvCDR::process_record()
+{
+	check_file_size_and_open();
+	bool retval = 0;
+	
+	// Format the call record and proceed from here...
+	outputfile << "\"" << callstartdate << "\",\"";
+	outputfile << callanswerdate << "\",\"";
+	outputfile << callenddate << "\",\"";
+	outputfile << hangupcause_text << "\",\"";
+	outputfile << hangupcause << "\",\"";
+	outputfile << clid << "\",\"";
+	outputfile << originated << "\",\"";
+	outputfile << dialplan << "\",\"";
+	outputfile << myuuid << "\",\"";
+	outputfile << destuuid << "\",\"";
+	outputfile << src << "\",\"";
+	outputfile << dst << "\",\"";
+	outputfile << srcchannel << "\",\"";
+	outputfile << dstchannel << "\",\"";
+	outputfile << ani << "\",\"";
+	outputfile << ani2 << "\",\"";
+	outputfile << network_addr << "\",\"";
+	outputfile << lastapp << "\",\"";
+	outputfile << lastdata << "\",\"";
+	outputfile << billusec << "\",\"";
+	outputfile << disposition << "\",\"";
+	outputfile << amaflags << "\"";
+	
+	// Now to process chanvars, fixed ones first
+	if(chanvars_fixed.size() > 0 )
+	{
+		std::list<std::pair<std::string,std::string> >::iterator iItr, iEnd;
+		for(iItr = chanvars_fixed.begin(), iEnd = chanvars_fixed.end(); iItr != iEnd; iItr++)
+			outputfile << ",\"" << iItr->second << "\"";
+	}
+		
+	if(chanvars_supp.size() > 0 )
+	{
+		std::map<std::string,std::string>::iterator iItr,iEnd;
+		for(iItr = chanvars_supp.begin(), iEnd = chanvars_supp.end() ; iItr != iEnd; iItr++)
+			outputfile << ",\"" << iItr->first << "=" << iItr->second << "\"";
+	}
+	outputfile << std::endl;
+	retval = 1;
+		
+	return retval;
+}
+
+bool CsvCDR::is_activated()
+{
+	return activated;
+}
+
+void CsvCDR::tempdump_record()
+{
+
+}
+
+void CsvCDR::reread_tempdumped_records()
+{
+
+}
+
+void CsvCDR::disconnect()
+{
+	outputfile.close();
+	switch_console_printf(SWITCH_CHANNEL_LOG,"Shutting down CsvCDR...  Done!");	
+}
+
+AUTO_REGISTER_BASECDR(CsvCDR);

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/csvcdr.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/csvcdr.h	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,77 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ header file describes the CsvCDR class that handles processing CDRs to a CSV format.
+ * This is the standard CSV module, and has a list of predefined variables to log out which can be
+ * added to, but never have the default ones removed.  If you want to use one that allows you to explicity
+ * set all data variables to be logged and in what order, then this is not the class you want to use, and
+ * one will be coming in the future to do just that.
+ *
+ * csvcdr.h
+ *
+ */
+
+#include "baseregistry.h"
+#include <switch.h>
+#include <iostream>
+#include <fstream>
+#include <list>
+
+#ifndef CSVCDR
+#define CSVCDR
+
+class CsvCDR : public BaseCDR {
+	public:
+		CsvCDR();
+		CsvCDR(switch_mod_cdr_newchannel_t *newchannel);
+		//CsvCDR(const CsvCDR& copyFrom);
+		virtual ~CsvCDR();
+		virtual bool process_record();
+		virtual void connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param); // connect and disconnect need to be static because we're persisting connections until shutdown
+		virtual void disconnect();
+		virtual bool is_activated();
+		virtual void tempdump_record();
+		virtual void reread_tempdumped_records();
+
+	private:
+		static bool activated; // Is this module activated?
+		static bool connectionstate; // What is the status of the connection?
+		static bool logchanvars;
+		static bool repeat_fixed_in_supp; // Repeat the fixed chanvars in the supplemental?
+		static std::string outputfile_path; // The directory we'll dump these into
+		static std::list<std::string> chanvars_fixed_list; // Normally this would be used, but not in this class
+		static std::list<std::string> chanvars_supp_list; // This will hold the list for all chanvars here
+		char formattedcallstartdate[100];
+		char formattedcallanswerdate[100];
+		char formattedcallenddate[100];
+		static std::ofstream outputfile;
+		static std::ofstream::pos_type filesize_limit;
+		void check_file_size_and_open(); // Checks the size of the file, and if it's greater than size allowed, rotates it.
+		void open_file();
+};
+
+#endif

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/mod_cdr.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/mod_cdr.cpp	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,107 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This source file describes the most basic portions of the CDR module.  These are the functions
+ * and structures that the Freeswitch core looks for when opening up the DSO file to create the load, shutdown
+ * and runtime threads as necessary.
+ *
+ * mod_cdr.cpp
+ *
+ */
+
+#include "cdrcontainer.h"
+#include <switch.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+static const char modname[] = "mod_cdr - CDR Engine";
+static int RUNNING = 0;
+static CDRContainer *newcdrcontainer;
+static switch_memory_pool_t *module_pool;
+static switch_status_t my_on_hangup(switch_core_session_t *session);
+
+/* Now begins the glue that will tie this into the system.
+*/
+
+static const switch_state_handler_table_t state_handlers = {
+	/*.on_init */ NULL,
+	/*.on_ring */ NULL,
+	/*.on_execute */ NULL,
+	/*.on_hangup */ my_on_hangup,
+	/*.on_loopback */ NULL,
+	/*.on_transmit */ NULL
+};
+
+static const switch_loadable_module_interface_t cdr_module_interface = {
+	/*.module_name */ modname,
+	/*.endpoint_interface */ NULL,
+	/*.timer_interface */ NULL,
+	/*.dialplan_interface */ NULL,
+	/*.codec_interface */ NULL,
+	/*.application_interface */ NULL
+};
+
+static switch_status_t my_on_hangup(switch_core_session_t *session)
+{
+	newcdrcontainer->add_cdr(session);
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface **interface, char *filename)
+{
+	/* connect my internal structure to the blank pointer passed to me */
+	*interface = &cdr_module_interface;
+	
+	switch_core_add_state_handler(&state_handlers);
+	
+	if (switch_core_new_memory_pool(&module_pool) != SWITCH_STATUS_SUCCESS) 
+	{
+		switch_console_printf(SWITCH_CHANNEL_LOG, "OH OH - Can't swim, no pool\n");
+		return SWITCH_STATUS_TERM;
+	}
+
+	newcdrcontainer = new CDRContainer(module_pool);  // Instantiates the new object, automatically loads config
+	
+	/* indicate that the module should continue to be loaded */
+	return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_runtime(void)
+{
+	RUNNING = 1;
+	switch_console_printf(SWITCH_CHANNEL_LOG, "mod_cdr made it to runtime.  Wee!\n");
+	newcdrcontainer->process_records();
+	
+	return RUNNING ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_TERM;
+}
+
+SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
+{
+	delete newcdrcontainer;
+	return SWITCH_STATUS_SUCCESS;
+}

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/mod_cdr.vcproj
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/mod_cdr.vcproj	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+	ProjectType="Visual C++"
+	Version="8.00"
+	Name="mod_cdr"
+	ProjectGUID="{3D1EED36-A510-4EDB-B4D9-4E0F4A5EC2A8}"
+	RootNamespace="mod_cdr"
+	Keyword="Win32Proj"
+	>
+	<Platforms>
+		<Platform
+			Name="Win32"
+		/>
+	</Platforms>
+	<ToolFiles>
+	</ToolFiles>
+	<Configurations>
+		<Configuration
+			Name="Debug|Win32"
+			OutputDirectory="Debug"
+			IntermediateDirectory="Debug"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				Optimization="0"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				MinimalRebuild="true"
+				BasicRuntimeChecks="3"
+				RuntimeLibrary="3"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="4"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_cdr.dll"
+				LinkIncremental="2"
+				AdditionalLibraryDirectories="..\..\..\..\w32\vsnet\$(OutDir)"
+				GenerateDebugInformation="true"
+				ProgramDatabaseFile="$(OutDir)/mod_cdr.pdb"
+				SubSystem="2"
+				ImportLibrary="$(OutDir)/mod_cdr.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+		<Configuration
+			Name="Release|Win32"
+			OutputDirectory="Release"
+			IntermediateDirectory="Release"
+			ConfigurationType="2"
+			InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
+			CharacterSet="2"
+			>
+			<Tool
+				Name="VCPreBuildEventTool"
+			/>
+			<Tool
+				Name="VCCustomBuildTool"
+			/>
+			<Tool
+				Name="VCXMLDataGeneratorTool"
+			/>
+			<Tool
+				Name="VCWebServiceProxyGeneratorTool"
+			/>
+			<Tool
+				Name="VCMIDLTool"
+			/>
+			<Tool
+				Name="VCCLCompilerTool"
+				AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"
+				PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
+				RuntimeLibrary="2"
+				UsePrecompiledHeader="0"
+				WarningLevel="4"
+				WarnAsError="true"
+				Detect64BitPortabilityProblems="true"
+				DebugInformationFormat="3"
+			/>
+			<Tool
+				Name="VCManagedResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCResourceCompilerTool"
+			/>
+			<Tool
+				Name="VCPreLinkEventTool"
+			/>
+			<Tool
+				Name="VCLinkerTool"
+				OutputFile="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_cdr.dll"
+				LinkIncremental="1"
+				AdditionalLibraryDirectories="..\..\..\..\w32\vsnet\$(OutDir)"
+				GenerateDebugInformation="true"
+				SubSystem="2"
+				OptimizeReferences="2"
+				EnableCOMDATFolding="2"
+				ImportLibrary="$(OutDir)/mod_cdr.lib"
+				TargetMachine="1"
+			/>
+			<Tool
+				Name="VCALinkTool"
+			/>
+			<Tool
+				Name="VCManifestTool"
+			/>
+			<Tool
+				Name="VCXDCMakeTool"
+			/>
+			<Tool
+				Name="VCBscMakeTool"
+			/>
+			<Tool
+				Name="VCFxCopTool"
+			/>
+			<Tool
+				Name="VCAppVerifierTool"
+			/>
+			<Tool
+				Name="VCWebDeploymentTool"
+			/>
+			<Tool
+				Name="VCPostBuildEventTool"
+			/>
+		</Configuration>
+	</Configurations>
+	<References>
+	</References>
+	<Files>
+		<Filter
+			Name="Source Files"
+			Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+			>
+			<File
+				RelativePath=".\basecdr.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\baseregistry.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\cdrcontainer.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\csvcdr.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\mod_cdr.cpp"
+				>
+			</File>
+			<File
+				RelativePath=".\pddcdr.cpp"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Header Files"
+			Filter="h;hpp;hxx;hm;inl;inc;xsd"
+			UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+			>
+			<File
+				RelativePath=".\basecdr.h"
+				>
+			</File>
+			<File
+				RelativePath=".\baseregistry.h"
+				>
+			</File>
+			<File
+				RelativePath=".\cdrcontainer.h"
+				>
+			</File>
+			<File
+				RelativePath=".\csvcdr.h"
+				>
+			</File>
+			<File
+				RelativePath=".\pddcdr.h"
+				>
+			</File>
+		</Filter>
+		<Filter
+			Name="Resource Files"
+			Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
+			UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+			>
+		</Filter>
+	</Files>
+	<Globals>
+	</Globals>
+</VisualStudioProject>

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/mysqlcdr.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/mysqlcdr.cpp	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,602 @@
+/*
+* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+*
+* Copyright 2006, Author: Yossi Neiman, president of Cartis Solutions, Inc. 
+* <freeswitch AT cartissolutions.com>
+*
+* Description: This C++ source file describes the MysqlCDR class which handles formatting a CDR out to
+* a MySQL 4.1.x or greater server using prepared statements.
+*
+*
+* Version: MPL 1.1
+* The contents of this file are subject to the Mozilla Public License Version
+* 1.1 (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+* http://www.mozilla.org/MPL/
+*
+* Software distributed under the License is distributed on an "AS IS" basis,
+* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+* for the specific language governing rights and limitations under the
+* License
+*
+* The Core API is the FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application by
+* Anthony Minnesale II <anthmct at yahoo.com>
+*
+* mysqlcdr.cpp
+*
+*/
+
+#include <mysql.h>
+#include <switch.h>
+#include <cstring>
+#include <iostream>
+#include "mysqlcdr.h"
+
+MysqlCDR::MysqlCDR() : BaseCDR()
+{
+
+}
+
+MysqlCDR::MysqlCDR(switch_mod_cdr_newchannel_t *newchannel) : BaseCDR(newchannel)
+{
+	if(newchannel != 0)
+	{
+		clid_length = strlen(clid);
+		src_length = strlen(src);
+		dst_length = strlen(dst);
+		ani_length = strlen(ani);
+		ani2_length = strlen(ani2);
+		dialplan_length = strlen(dialplan);
+		myuuid_length = strlen(myuuid);
+		destuuid_length = strlen(destuuid);
+		srcchannel_length = strlen(srcchannel);
+		dstchannel_length = strlen(dstchannel);
+		lastapp_length = strlen(lastapp);
+		lastdata_length = strlen(lastdata);
+		
+		if(chanvars_fixed_list.size() > 0)
+			process_channel_variables(chanvars_fixed_list,newchannel->channel);
+		
+		if(chanvars_supp_list.size() > 0)
+			process_channel_variables(chanvars_supp_list,chanvars_fixed_list,newchannel->channel,repeat_fixed_in_supp);
+	}	
+}
+
+MysqlCDR::~MysqlCDR()
+{
+
+}
+
+bool MysqlCDR::connectionstate = 0;
+bool MysqlCDR::logchanvars = 0;
+bool MysqlCDR::repeat_fixed_in_supp = 0;
+std::list<std::string> MysqlCDR::chanvars_fixed_list;
+std::list<std::string> MysqlCDR::chanvars_supp_list;
+std::vector<switch_mod_cdr_sql_types_t> MysqlCDR::chanvars_fixed_types;
+bool MysqlCDR::activated = 0;
+char* MysqlCDR::sql_query = 0;
+std::string MysqlCDR::tmp_sql_query;
+char MysqlCDR::sql_query_chanvars[100] = "";
+MYSQL* MysqlCDR:: conn = 0;
+MYSQL_STMT* MysqlCDR::stmt=0;
+MYSQL_STMT* MysqlCDR::stmt_chanvars=0;
+char MysqlCDR::hostname[255] = "";
+char MysqlCDR::username[255] ="";
+char MysqlCDR::dbname[255] = "";
+char MysqlCDR::password[255] = "";
+//fstream MysqlCDR::tmpfile;
+
+void MysqlCDR::connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param)
+{
+	if(activated)
+		disconnect();
+	
+	activated = 0; // Set it as inactive initially
+	connectionstate = 0; // Initialize it to false to show that we aren't yet connected.
+	
+	int count_config_params = 0;  // Need to make sure all params are set before we load
+	if ((settings = switch_xml_child(cfg, "mysqlcdr"))) 
+	{
+		for (param = switch_xml_child(settings, "param"); param; param = param->next) 
+		{
+			char *var = (char *) switch_xml_attr_soft(param, "name");
+			char *val = (char *) switch_xml_attr_soft(param, "value");
+
+			if (!strcmp(var, "hostname"))
+			{
+				if(val != 0)
+				{
+					strncpy(hostname,val,strlen(val));
+					count_config_params++;
+				}
+			}
+			else if (!strcmp(var, "username")) 
+			{
+				if(val != 0)
+				{
+					strncpy(username,val,strlen(val));
+					count_config_params++;
+				}
+			}
+			else if (!strcmp(var,"password"))
+			{
+				if(val != 0)
+				{
+					strncpy(password,val,strlen(val));
+					count_config_params++;
+				}
+			}
+			else if(!strcmp(var,"dbname"))
+			{
+				if(val != 0)
+				{
+					strncpy(dbname,val,strlen(val));
+					count_config_params++;
+				}
+			}
+			else if(!strcmp(var,"chanvars_fixed"))
+			{
+				std::string unparsed;
+				unparsed = val;
+				if(unparsed.size() > 0)
+				{
+					parse_channel_variables_xconfig(unparsed,chanvars_fixed_list,chanvars_fixed_types);
+					//logchanvars=1;
+				}
+			}
+			else if(!strcmp(var,"chanvars_supp"))
+			{
+				if(val != 0)
+				{
+					std::string unparsed = val;
+					bool fixed = 0;
+					logchanvars = 1;
+					parse_channel_variables_xconfig(unparsed,chanvars_supp_list,fixed);
+				}	
+			}
+			else if(!strcmp(var,"chanvars_supp_repeat_fixed"))
+			{
+				if(val != 0)
+				{
+					std::string repeat = val;
+					if(repeat == "Y" || repeat == "y" || repeat == "1")
+						repeat_fixed_in_supp = 1;
+				}
+			}
+		}
+		
+		if (count_config_params==4)
+			activated = 1;
+		else
+			switch_console_printf(SWITCH_CHANNEL_LOG,"You did not specify the minimum parameters for using this module.  You must specify a hostname, username, password, and database to use MysqlCDR.  You only supplied %d parameters.\n",count_config_params);
+		
+		if(activated)
+		{
+			tmp_sql_query = "INSERT INTO freeswitchcdr  (callstartdate,callanswerdate,callenddate,originated,clid,src,dst,ani,ani2,dialplan,myuuid,destuuid,srcchannel,dstchannel,lastapp,lastdata,billusec,disposition,hangupcause,amaflags";
+			
+			int items_appended = 0;
+			
+			if(chanvars_fixed_list.size() > 0 )
+			{
+				std::list<std::string>::iterator iItr, iEnd;
+				for(iItr = chanvars_fixed_list.begin(), iEnd = chanvars_fixed_list.end(); iItr != iEnd; iItr++)
+				{
+					if(iItr->size() > 0)
+					{
+						tmp_sql_query.append(",");
+						tmp_sql_query.append(*iItr);
+						items_appended++;
+					}
+				}
+			}
+			
+			tmp_sql_query.append(") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?");
+			
+			if(chanvars_fixed_list.size() > 0 )
+			{
+				for(int i = 0; i < items_appended; i++)
+					tmp_sql_query.append(",?");
+			}
+			
+			tmp_sql_query.append(")");
+			
+			std::vector<char> tempfirstvector(tmp_sql_query.begin(), tmp_sql_query.end());
+			tempfirstvector.push_back('\0');
+			sql_query = &tempfirstvector[0];
+	
+			char tempsql_query_chanvars[] = "INSERT INTO chanvars (callid,varname,varvalue) VALUES(?,?,?)";
+			memset(sql_query_chanvars,0,100);
+			strncpy(sql_query_chanvars,tempsql_query_chanvars,strlen(tempsql_query_chanvars));
+
+			conn = mysql_init(NULL);
+			mysql_options(conn, MYSQL_READ_DEFAULT_FILE, "");
+			if(mysql_real_connect(conn,hostname,username,password,dbname,0,NULL,0) == NULL)
+			{
+				char *error1 = "Cannot connect to MySQL Server.  The error was: ";
+				const char *error2 = mysql_error(conn);
+				strncat(error1,error2,strlen(error2));
+				switch_console_printf(SWITCH_CHANNEL_LOG,error1);
+			}
+			else
+				connectionstate = 1;
+	
+			mysql_autocommit(conn,0);
+			stmt = mysql_stmt_init(conn);
+		
+			mysql_stmt_prepare(stmt,sql_query,strlen(sql_query));
+		
+			if(logchanvars)
+			{
+				stmt_chanvars = mysql_stmt_init(conn);
+				mysql_stmt_prepare(stmt_chanvars,sql_query_chanvars,strlen(sql_query_chanvars));
+			}
+		}
+	}
+}
+
+bool MysqlCDR::is_activated()
+{
+	return activated;
+}
+
+template <typename T> 
+void MysqlCDR::add_parameter(T& param, enum_field_types type, bool *is_null)
+{
+	MYSQL_BIND temp_bind;
+	memset(&temp_bind,0,sizeof(temp_bind));
+	
+        temp_bind.buffer_type = type;
+	if(is_null != 0)
+	{
+	        if(*is_null)
+	                temp_bind.is_null = (my_bool*) is_null;
+		else
+			temp_bind.buffer = &param;
+	}
+	else
+		temp_bind.buffer = &param;
+
+	bindme.push_back(temp_bind);
+}
+
+template <>
+void MysqlCDR::add_parameter<MYSQL_TIME>(MYSQL_TIME& param, enum_field_types type, bool* is_null)
+{
+	MYSQL_BIND temp_bind;
+	memset(&temp_bind,0,sizeof(temp_bind));
+	
+	temp_bind.buffer_type = type;
+	if(is_null != 0)
+	{
+		if(*is_null)
+			temp_bind.is_null = (my_bool*) is_null;
+		else
+			temp_bind.buffer = &param;
+
+	}
+	else
+		temp_bind.buffer = &param;
+	
+	bindme.push_back(temp_bind);
+}
+
+void MysqlCDR::tempdump_record()
+{
+
+}
+
+void MysqlCDR::reread_tempdumped_records()
+{
+
+}
+
+
+bool MysqlCDR::process_record()
+{
+	switch_time_exp_t tm1,tm2,tm3; // One for call start
+	memset(&tm1,0,sizeof(tm1));
+	memset(&tm2,0,sizeof(tm2));
+	memset(&tm3,0,sizeof(tm3));
+	
+	switch_time_exp_lt(&tm1,callstartdate);
+	switch_time_exp_lt(&tm2,callanswerdate);
+	switch_time_exp_lt(&tm3,callenddate);
+	
+	set_mysql_time(tm1,my_callstartdate);
+	set_mysql_time(tm2,my_callanswerdate);
+	set_mysql_time(tm3,my_callenddate);
+	
+	add_parameter(my_callstartdate,MYSQL_TYPE_DATETIME);
+	add_parameter(my_callanswerdate,MYSQL_TYPE_DATETIME);
+	add_parameter(my_callenddate,MYSQL_TYPE_DATETIME);
+	
+	add_parameter(originated,MYSQL_TYPE_TINY);
+	add_string_parameter(clid,clid_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(src,src_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(dst,dst_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(ani,ani_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(ani2,ani2_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(dialplan,dialplan_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(myuuid,myuuid_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(destuuid,destuuid_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(srcchannel,srcchannel_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(dstchannel,dstchannel_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(lastapp,lastapp_length,MYSQL_TYPE_VAR_STRING,0);
+	add_string_parameter(lastdata,lastdata_length,MYSQL_TYPE_VAR_STRING,0);
+	add_parameter(billusec,MYSQL_TYPE_LONGLONG,0);
+	add_parameter(disposition,MYSQL_TYPE_TINY,0);
+	add_parameter(hangupcause,MYSQL_TYPE_LONG,0);
+	add_parameter(amaflags,MYSQL_TYPE_TINY,0);
+		
+	std::list<void*> temp_chanvars_holder; // This is used for any fixed chanvars, as we don't want things out of scope
+	
+	if(chanvars_fixed_list.size() > 0)
+	{
+		switch_size_t i = 0; // temporary variable, i is current spot on the string of types
+		std::list<std::pair<std::string,std::string> >::iterator iItr, iEnd;
+		for(iItr = chanvars_fixed.begin(), iEnd = chanvars_fixed.end(); iItr != iEnd; iItr++)
+		{	
+			switch(chanvars_fixed_types[i])
+			{
+				case CDR_INTEGER: 
+				{
+					int* x = new int;
+					*x = 0;
+					bool* is_null = new bool;
+					*is_null = 0;
+					
+					if(iItr->second.size() > 0)
+					{
+						std::istringstream istring(iItr->second);
+						istring >> *x;
+					}
+					else
+						*is_null = 1;
+					temp_chanvars_holder.push_back(x);
+					temp_chanvars_holder.push_back(is_null);
+					add_parameter(*x,MYSQL_TYPE_LONG,is_null);
+					break;
+				}
+				case CDR_DOUBLE: 
+				{
+					double* x = new double;
+					*x = 0;
+					bool* is_null = new bool;
+					*is_null = 0;
+					if(iItr->second.size() > 0)
+					{
+						std::istringstream istring(iItr->second);
+						istring >> *x;
+					}
+					else
+						*is_null = 1;
+					temp_chanvars_holder.push_back(x);
+					temp_chanvars_holder.push_back(is_null);
+					add_parameter(*x,MYSQL_TYPE_DOUBLE,is_null);
+					break;
+				}
+				case CDR_TINY:
+				{
+					short* x = new short;
+					*x = 0;
+					bool* is_null = new bool;
+					*is_null = 0;
+					std::cout << "CDR_TINY: " << iItr->second << " and its size is " << iItr->second.size() << " bytes." << std::endl << std::endl;
+					if(iItr->second.size() > 0)
+					{
+						std::cout << "Converting iItr->second to type char." << std::endl;
+						std::istringstream istring(iItr->second);
+						istring >> *x;
+					}
+					else
+						*is_null = 1;
+					temp_chanvars_holder.push_back(x);
+					temp_chanvars_holder.push_back(is_null);
+					add_parameter(*x,MYSQL_TYPE_TINY,is_null);
+					break;
+				}
+				case CDR_STRING:
+				case CDR_DECIMAL:
+				{
+					long unsigned int* stringlength = new long unsigned int;
+					*stringlength = iItr->second.size();
+				
+					char* x = new char[(*stringlength+1)];
+					strncpy(x,iItr->second.c_str(),*stringlength);
+					
+					bool* is_null = new bool;
+					*is_null = 0;
+					add_string_parameter(x,*stringlength,MYSQL_TYPE_VAR_STRING,is_null);
+				
+					temp_chanvars_holder.push_back(stringlength);
+					temp_chanvars_holder.push_back(x);
+					temp_chanvars_holder.push_back(is_null);
+					break;
+				}
+				default:
+					switch_console_printf(SWITCH_CHANNEL_LOG,"We should not get to this point in this switch/case statement.\n");
+			}
+			i++;
+		}
+	}
+		
+	MYSQL_BIND *bindmetemp;
+	bindmetemp = new MYSQL_BIND[bindme.size()];
+	copy(bindme.begin(), bindme.end(), bindmetemp);
+	
+	mysql_stmt_bind_param(stmt,bindmetemp);
+	int bah = mysql_stmt_execute(stmt);
+	switch_console_printf(SWITCH_CHANNEL_LOG,"MysqlCDR::process_record() - Statement executed? Error: %d\n",bah);
+	
+	const char* bah2 = mysql_stmt_error(stmt);
+	switch_console_printf(SWITCH_CHANNEL_LOG,"MySQL encountered error: %s\n",bah2);
+		
+	if(logchanvars && chanvars_supp.size() > 0)
+	{
+		long long insertid = mysql_stmt_insert_id(stmt);
+
+		std::map<std::string,std::string>::iterator iItr,iBeg,iEnd;
+		iEnd = chanvars_supp.end();
+		for(iItr = chanvars_supp.begin(); iItr != iEnd; iItr++)
+		{
+			MYSQL_BIND bindme_chanvars[3];
+			memset(bindme_chanvars,0,sizeof(bindme_chanvars));
+			
+			bindme_chanvars[0].buffer_type = MYSQL_TYPE_LONGLONG;
+			bindme_chanvars[0].buffer = &insertid;
+			
+			std::vector<char> tempfirstvector(iItr->first.begin(), iItr->first.end());
+			tempfirstvector.push_back('\0');
+			char* varname_temp = &tempfirstvector[0];
+
+			bindme_chanvars[1].buffer_type = MYSQL_TYPE_VAR_STRING;
+			long unsigned int varname_length = iItr->first.size();
+			bindme_chanvars[1].length = &varname_length;
+			bindme_chanvars[1].buffer_length = varname_length;
+			bindme_chanvars[1].buffer = varname_temp;
+			
+			std::vector<char> tempsecondvector(iItr->second.begin(), iItr->second.end());
+			tempsecondvector.push_back('\0');
+			char* varvalue_temp = &tempsecondvector[0];
+			
+			bindme_chanvars[2].buffer_type = MYSQL_TYPE_VAR_STRING;
+			if(iItr->second.size() == 0)
+				bindme_chanvars[2].is_null = (my_bool*)1;
+			else
+			{
+				long unsigned int varvalue_length = iItr->second.size();
+				bindme_chanvars[2].length = &varvalue_length;
+				bindme_chanvars[2].buffer_length = varvalue_length;
+				bindme_chanvars[2].buffer = varvalue_temp;
+			}
+			
+			mysql_stmt_bind_param(stmt_chanvars,bindme_chanvars);
+			mysql_stmt_execute(stmt_chanvars);
+		}
+	}
+	
+	
+	mysql_commit(conn);
+	
+	/* For future use
+	if(!mysql_stmt_execute(stmt))
+	{
+		if(errorstate == TRUE)
+			reprocess_tempdumped_data();
+		mysql_commit(conn);
+		errorstate=FALSE();
+	}
+	else
+	{
+		errorstate = TRUE;
+		mysql_rollback(conn);
+		tempdump_data();
+	}
+	*/
+	
+	delete [] bindmetemp;
+	if(temp_chanvars_holder.size() > 0)
+	{
+		std::string::size_type i = 0, j = chanvars_fixed_types.size();
+		for(; i < j ; i++)
+		{
+			switch(chanvars_fixed_types[i])
+			{
+				case CDR_STRING:
+				case CDR_DECIMAL:
+				{
+					long unsigned int* stringlength = (long unsigned int*)temp_chanvars_holder.front();
+					temp_chanvars_holder.pop_front();
+					delete stringlength;
+					char* tempstring = (char*) temp_chanvars_holder.front();
+					temp_chanvars_holder.pop_front();
+					delete [] tempstring;
+					break;
+				}
+				case CDR_INTEGER:
+				{
+					int* tempint = (int*) temp_chanvars_holder.front();
+					temp_chanvars_holder.pop_front();
+					delete tempint;
+					break;
+				}
+				case CDR_DOUBLE:
+				{
+					double* tempdouble = (double*) temp_chanvars_holder.front();
+					temp_chanvars_holder.pop_front();
+					delete tempdouble;
+					break;
+				}
+				case CDR_TINY:
+				{	
+					short* tempshort = (short*) temp_chanvars_holder.front();
+					temp_chanvars_holder.pop_front();
+					delete tempshort;
+					break;
+				}
+				default:
+					switch_console_printf(SWITCH_CHANNEL_LOG,"We should not get to this point in this switch/case statement.\n");
+			}
+			
+			bool* tempbool = (bool*) temp_chanvars_holder.front();
+			temp_chanvars_holder.pop_front();
+			delete tempbool;
+		}
+	}
+	return 1;
+}
+
+void MysqlCDR::disconnect()
+{
+	mysql_stmt_close(stmt);
+	if(logchanvars)
+		mysql_stmt_close(stmt_chanvars);
+	mysql_close(conn);
+	activated = 0;
+	logchanvars = 0;
+	chanvars_fixed_list.clear();
+	chanvars_supp_list.clear();
+	chanvars_fixed_types.clear();
+	connectionstate = 0;
+	tmp_sql_query.clear();
+}
+
+
+
+void MysqlCDR::add_string_parameter(char* param, long unsigned int& param_length, enum_field_types type, bool *is_null)
+{
+	MYSQL_BIND temp_bind;
+	memset(&temp_bind,0,sizeof(temp_bind));
+	temp_bind.buffer_type = type;
+	if(is_null != 0)
+	{
+		if(*is_null || param == 0)
+			temp_bind.is_null = (my_bool*) is_null;
+		else
+		{
+			temp_bind.length = &param_length;
+			temp_bind.buffer_length = param_length;
+			temp_bind.buffer = param;
+		}
+	}
+	else
+	{
+		temp_bind.length = &param_length;
+		temp_bind.buffer_length = param_length;
+		temp_bind.buffer = param;
+	}
+
+	bindme.push_back(temp_bind);
+}
+
+void MysqlCDR::set_mysql_time(switch_time_exp_t& param, MYSQL_TIME& destination)
+{
+	destination.year = param.tm_year + 1900;
+	destination.month = param.tm_mon + 1;
+	destination.day = param.tm_mday;
+	destination.hour = param.tm_hour;
+	destination.minute = param.tm_min;
+	destination.second = param.tm_sec;	
+}
+
+AUTO_REGISTER_BASECDR(MysqlCDR);

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/mysqlcdr.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/mysqlcdr.h	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,93 @@
+/*
+* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+*
+* Copyright 2006, Author: Yossi Neiman, president of Cartis Solutions, Inc. 
+* <freeswitch AT cartissolutions.com>
+*
+* Description: This C++ header file describes the MysqlCDR class which handles formatting a CDR out to
+* a MySQL 4.1.x or greater server using prepared statements.
+*
+*
+* Version: MPL 1.1
+* The contents of this file are subject to the Mozilla Public License Version
+* 1.1 (the "License"); you may not use this file except in compliance with
+* the License. You may obtain a copy of the License at
+* http://www.mozilla.org/MPL/
+*
+* Software distributed under the License is distributed on an "AS IS" basis,
+* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+* for the specific language governing rights and limitations under the
+* License
+*
+* The Core API is the FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application by
+* Anthony Minnesale II <anthmct at yahoo.com>
+*
+* mysqlcdr.h
+*
+*/
+
+#include "baseregistry.h"
+#include <list>
+#include <sstream>
+#include <mysql.h>
+
+#ifndef MYSQLCDR
+#define MYSQLCDR
+
+class MysqlCDR : public BaseCDR {
+	public:
+		MysqlCDR();
+		MysqlCDR(switch_mod_cdr_newchannel_t *newchannel);
+		//MysqlCDR(const MysqlCDR& copyFrom);
+		virtual ~MysqlCDR();
+		virtual bool process_record();
+		virtual void connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param);
+		virtual void disconnect();
+		virtual bool is_activated();
+		virtual void tempdump_record();
+		virtual void reread_tempdumped_records();
+
+	private:
+		static bool activated;
+		static char *sql_query;
+		static std::string tmp_sql_query; // Object must exist to bind the statement, this used for generating the sql
+		static char sql_query_chanvars[100];
+		static MYSQL *conn;
+		static MYSQL_STMT *stmt;
+		static MYSQL_STMT *stmt_chanvars;
+		static bool connectionstate;
+		static bool logchanvars;
+		static std::list<std::string> chanvars_fixed_list;
+		static std::vector<switch_mod_cdr_sql_types_t> chanvars_fixed_types;
+		static std::list<std::string> chanvars_supp_list; // The supplemental list
+		static bool repeat_fixed_in_supp;
+		static char hostname[255];
+		static char username[255];
+		static char dbname[255];
+		static char password[255];
+		//static fstream tmpfile;
+		std::vector<MYSQL_BIND> bindme;
+		//MYSQL_BIND *bindme;
+		MYSQL_TIME my_callstartdate;
+		MYSQL_TIME my_callanswerdate;
+		MYSQL_TIME my_callenddate;
+		// Why all these long unsigned int's?  MySQL's prep statement API expects these to actually exist and not just be params passed to the function calls.  The are to measure the length of actual data in the char* arrays.
+		long unsigned int clid_length;
+		long unsigned int dialplan_length;
+		long unsigned int myuuid_length;
+		long unsigned int destuuid_length;
+		long unsigned int src_length;
+		long unsigned int dst_length;
+		long unsigned int srcchannel_length;
+		long unsigned int dstchannel_length;
+		long unsigned int ani_length;
+		long unsigned int ani2_length;
+		long unsigned int lastapp_length;
+		long unsigned int lastdata_length;
+		// Now a couple internal methods
+		template <typename T> void add_parameter(T& param, enum_field_types type, bool *is_null=0);
+		void add_string_parameter(char* param, long unsigned int& param_length, enum_field_types type, bool* is_null=0);
+		void set_mysql_time(switch_time_exp_t& param, MYSQL_TIME& destination);
+};
+
+#endif

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/pddcdr.cpp
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/pddcdr.cpp	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,216 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ source file describes the PddCDR class which handles formatting a CDR out to
+ * individual text files in a Perl Data Dumper format.
+ *
+ * pddcdr.cpp
+ *
+ */
+
+#include <switch.h>
+#include "pddcdr.h"
+
+PddCDR::PddCDR() : BaseCDR()
+{
+	memset(formattedcallstartdate,0,100);
+	memset(formattedcallanswerdate,0,100);
+	memset(formattedcallenddate,0,100);
+}
+
+PddCDR::PddCDR(switch_mod_cdr_newchannel_t *newchannel) : BaseCDR(newchannel)
+{
+	memset(formattedcallstartdate,0,100);
+	memset(formattedcallanswerdate,0,100);
+	memset(formattedcallenddate,0,100);
+	
+	if(newchannel != 0)
+	{
+		switch_time_exp_t tempcallstart, tempcallanswer, tempcallend;
+		memset(&tempcallstart,0,sizeof(tempcallstart));
+		memset(&tempcallanswer,0,sizeof(tempcallanswer));
+		memset(&tempcallend,0,sizeof(tempcallend));
+		switch_time_exp_lt(&tempcallstart, callstartdate);
+		switch_time_exp_lt(&tempcallanswer, callanswerdate);
+		switch_time_exp_lt(&tempcallend, callenddate);
+		
+		// Format the times
+		size_t retsizecsd, retsizecad, retsizeced; //csd == callstartdate, cad == callanswerdate, ced == callenddate, ceff == callenddate_forfile
+		char format[] = "%F %T";
+		switch_strftime(formattedcallstartdate,&retsizecsd,sizeof(formattedcallstartdate),format,&tempcallstart);
+		switch_strftime(formattedcallanswerdate,&retsizecad,sizeof(formattedcallanswerdate),format,&tempcallanswer);
+		switch_strftime(formattedcallenddate,&retsizeced,sizeof(formattedcallenddate),format,&tempcallend);
+
+		std::ostringstream ostring;
+		ostring << (callenddate/1000000);
+		std::string callenddate_forfile = ostring.str();
+		
+		outputfile_name = outputfile_path;
+		outputfile_name.append(SWITCH_PATH_SEPARATOR);
+		outputfile_name.append(callenddate_forfile); // Make sorting a bit easier, kinda like Maildir does
+		outputfile_name.append(".");
+		outputfile_name.append(myuuid);  // The goal is to have a resulting filename of "/path/to/myuuid"
+		outputfile_name.append(".pdd");  // .pdd - "perl data dumper"
+	
+		outputfile.open(outputfile_name.c_str());
+	
+		bool repeat = 1;
+		process_channel_variables(chanvars_supp_list,chanvars_fixed_list,newchannel->channel,repeat);
+	}
+}
+
+PddCDR::~PddCDR()
+{
+	outputfile.close();	
+}
+
+bool PddCDR::activated=0;
+bool PddCDR::logchanvars=0;
+bool PddCDR::connectionstate=0;
+std::string PddCDR::outputfile_path;
+std::list<std::string> PddCDR::chanvars_fixed_list;
+std::list<std::string> PddCDR::chanvars_supp_list;
+
+void PddCDR::connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param)
+{
+	switch_console_printf(SWITCH_CHANNEL_LOG, "PddCDR::connect() - Loading configuration file.\n");
+	activated = 0; // Set it as inactive initially
+	connectionstate = 0; // Initialize it to false to show that we aren't yet connected.
+	
+	if ((settings = switch_xml_child(cfg, "pddcdr"))) 
+	{
+		int count_config_params = 0;  // Need to make sure all params are set before we load
+		for (param = switch_xml_child(settings, "param"); param; param = param->next) 
+		{
+			char *var = (char *) switch_xml_attr_soft(param, "name");
+			char *val = (char *) switch_xml_attr_soft(param, "value");
+
+			if (!strcmp(var, "path"))
+			{
+				if(val != 0)
+					outputfile_path = val;
+				count_config_params++;
+			}
+			else if (!strcmp(var, "chanvars")) 
+			{
+				if(val != 0)
+				{
+					std::string unparsed;
+					unparsed = val;
+					if(unparsed.size() > 0)
+					{
+						bool fixed = 0;
+						parse_channel_variables_xconfig(unparsed,chanvars_supp_list,fixed);
+						logchanvars=1;
+					}
+				}
+			}
+			else if (!strcmp(var, "chanvars_fixed"))
+			{
+				switch_console_printf(SWITCH_CHANNEL_LOG,"PddCDR has no need for a fixed or supplemental list of channel variables due to the nature of the format.  Please use the setting parameter of \"chanvars\" instead and try again.\n");
+			}
+			else if (!strcmp(var, "chanvars_supp"))
+			{
+				switch_console_printf(SWITCH_CHANNEL_LOG,"PddCDR has no need for a fixed or supplemental list of channel variables due to the nature of the format.  Please use the setting parameter of \"chanvars\" instead and try again.\n");
+			}
+		}
+		
+		if(count_config_params > 0)
+			activated = 1;
+		else
+			switch_console_printf(SWITCH_CHANNEL_LOG,"PddCDR::connect(): You did not specify the minimum parameters for using this module.  You must specify at least a path to have the records logged to.\n");
+	}
+}
+
+bool PddCDR::process_record()
+{
+	bool retval = 0;
+	if(!outputfile)
+		switch_console_printf(SWITCH_CHANNEL_LOG, "PddCDR::process_record():  Unable to open file  %s to commit the call record to.  Invalid path name, invalid permissions, or no space available?\n",outputfile_name.c_str());
+	else
+	{
+		// Format the call record and proceed from here...
+		outputfile << "$VAR1 = {" << std::endl;
+		outputfile << "\t\'callstartdate\' = \'" << callstartdate << "\'," << std::endl;
+		outputfile << "\t\'callanswerdate\' = \'" << callanswerdate << "\'," << std::endl;
+		outputfile << "\t\'callenddate\' = \'" << callenddate << "\'," << std::endl;
+		outputfile << "\t\'hangupcause\' = \'" << hangupcause_text << "\'," << std::endl;
+		outputfile << "\t\'hangupcausecode\' = \'" << hangupcause << "\'," << std::endl;
+		outputfile << "\t\'clid\' = \'" << clid << "\'," << std::endl;
+		outputfile << "\t\'originated\' = \'" << originated << "\'," << std::endl;
+		outputfile << "\t\'dialplan\' = \'" << dialplan << "\'," << std::endl;
+		outputfile << "\t\'myuuid\' = \'" << myuuid << "\'," << std::endl;
+		outputfile << "\t\'destuuid\' = \'" << destuuid << "\'," << std::endl;
+		outputfile << "\t\'src\' = \'" << src << "\'," << std::endl;
+		outputfile << "\t\'dst\' = \'" << dst << "\'," << std::endl;
+		outputfile << "\t\'srcchannel\' = \'" << srcchannel << "\'," << std::endl;
+		outputfile << "\t\'dstchannel\' = \'" << dstchannel << "\'," << std::endl;
+		outputfile << "\t\'ani\' = \'" << ani << "\'," << std::endl;
+		outputfile << "\t\'ani2\' = \'" << ani2 << "\'," << std::endl;
+		outputfile << "\t\'network_addr\' = \'" << network_addr << "\'," << std::endl;
+		outputfile << "\t\'lastapp\' = \'" << lastapp << "\'," << std::endl;
+		outputfile << "\t\'lastdata\' = \'" << lastdata << "\'," << std::endl;
+		outputfile << "\t\'billusec\' = \'" << billusec << "\'," << std::endl;
+		outputfile << "\t\'disposition\' = \'" << disposition << "\'," << std::endl;
+		outputfile << "\t\'amaflags\' = \'" << amaflags << "\'," << std::endl;
+		
+		// Now to process chanvars
+		outputfile << "\t\'chanvars\' => {" << std::endl;
+		if(chanvars_supp.size() > 0 )
+		{
+			std::map<std::string,std::string>::iterator iItr,iEnd;
+			for(iItr = chanvars_supp.begin(), iEnd = chanvars_supp.end() ; iItr != iEnd; iItr++)
+				outputfile << "\t\t\'" << iItr->first << "\' = \'" << iItr->second << "\'," << std::endl;
+		}
+		outputfile << "\t}," << std::endl << "};" << std::endl << std::endl;
+		retval = 1;
+	}
+	
+	return retval;
+}
+
+bool PddCDR::is_activated()
+{
+	return activated;
+}
+
+void PddCDR::tempdump_record()
+{
+
+}
+
+void PddCDR::reread_tempdumped_records()
+{
+
+}
+
+void PddCDR::disconnect()
+{
+	switch_console_printf(SWITCH_CHANNEL_LOG,"Shutting down PddCDR...  Done!");	
+}
+
+AUTO_REGISTER_BASECDR(PddCDR);

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/pddcdr.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/pddcdr.h	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,71 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. <freeswitch AT cartissolutions.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module
+ *
+ * The Initial Developer of the Original Code is
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Yossi Neiman <freeswitch AT cartissolutions.com>
+ *
+ * Description: This C++ header file describes the PddCDR class which handles formatting a CDR out to
+ * individual text files in a Perl Data Dumper format.
+ *
+ * pddcdr.h
+ *
+ */
+
+#include "baseregistry.h"
+#include <switch.h>
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <list>
+
+#ifndef PDDCDR
+#define PDDMCDR
+
+class PddCDR : public BaseCDR {
+	public:
+		PddCDR();
+		PddCDR(switch_mod_cdr_newchannel_t *newchannel);
+		virtual ~PddCDR();
+		virtual bool process_record();
+		virtual void connect(switch_xml_t& cfg, switch_xml_t& xml, switch_xml_t& settings, switch_xml_t& param); // connect and disconnect need to be static because we're persisting connections until shutdown
+		virtual void disconnect();
+		virtual bool is_activated();
+		virtual void tempdump_record();
+		virtual void reread_tempdumped_records();
+
+	private:
+		static bool activated; // Is this module activated?
+		static bool connectionstate; // What is the status of the connection?
+		static bool logchanvars;
+		static std::string outputfile_path; // The directory we'll dump these into
+		static std::list<std::string> chanvars_fixed_list; // Normally this would be used, but not in this class
+		static std::list<std::string> chanvars_supp_list; // This will hold the list for all chanvars here
+		char formattedcallstartdate[100];
+		char formattedcallanswerdate[100];
+		char formattedcallenddate[100];
+		std::string outputfile_name;
+		std::ofstream outputfile;
+};
+
+#endif

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/schema-update.mysql
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/schema-update.mysql	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,4 @@
+ALTER TABLE freeswitchcdr modify callid bigint unsigned auto_increment;
+ALTER TABLE freeswitchcdr Engine=InnoDB;
+
+ALTER TABLE chanvars Engine=InnoDB;
\ No newline at end of file

Added: freeswitch/trunk/src/mod/event_handlers/mod_cdr/schema.sql
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_cdr/schema.sql	Mon Jul 24 11:19:05 2006
@@ -0,0 +1,40 @@
+create table freeswitchcdr (
+	callid bigint unsigned default 0 primary key, /* This will need to be handled specially for auto increment, as that might not be standard */
+	callstartdate datetime NOT NULL,
+	callanswerdate datetime NOT NULL,
+	callenddate datetime NOT NULL,
+	originated tinyint default 0,
+	clid varchar(80) default "Freeswitch - Unknown",
+	src varchar(80) NOT NULL,
+	dst varchar(80) NOT NULL,
+	ani varchar(80) default "",
+	ani2 varchar(80) default "",
+	dialplan varchar(80) default "",
+	myuuid char(36) NOT NULL,
+	destuuid char(36) NOT NULL,
+	srcchannel varchar(80) NOT NULL,
+	dstchannel varchar(80) NOT NULL, /* Need to decide - this might be redundant as you can link the records via uuid */
+	lastapp varchar(80) default "",
+	lastdata varchar(255) default "",
+	billusec bigint default 0,
+	disposition tinyint default 0, /* 0 = Busy or Unanswered, 1 = Answered */
+	hangupcause int default 0,
+	amaflags tinyint default 0,
+	/*
+	This section not needed, because it was an old asteriskism.  A chan_var table is to replace it perhaps.
+	accountcode varchar(80) default "",
+	uniqueid varchar(32) default "",
+	userfield varchar(255) default ""
+	*/
+);
+
+create index myuuid_index on freeswitchcdr (myuuid);
+create index destuuid_index on freeswitchcdr (destuuid);
+
+create table chanvars (
+	callid bigint unsigned default 0,
+	varname varchar(80) NOT NULL,
+	varvalue varchar(255) default ""
+);
+
+create index callid_index on chanvars(callid,varname);
\ No newline at end of file

Modified: freeswitch/trunk/w32/vsnet/Freeswitch.sln
==============================================================================
--- freeswitch/trunk/w32/vsnet/Freeswitch.sln	(original)
+++ freeswitch/trunk/w32/vsnet/Freeswitch.sln	Mon Jul 24 11:19:05 2006
@@ -146,8 +146,8 @@
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_spidermonkey", "..\..\src\mod\languages\mod_spidermonkey\mod_spidermonkey.vcproj", "{1AD3F51E-BBB6-4090-BA39-9DFAB1EF1F5F}"
 	ProjectSection(ProjectDependencies) = postProject
-		{89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
 		{202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+		{89385C74-5860-4174-9CAF-A39E7C48909C} = {89385C74-5860-4174-9CAF-A39E7C48909C}
 	EndProjectSection
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ASR-TTS", "ASR-TTS", "{4CF6A6AC-07DE-4B9E-ABE1-7F98B64E0BB0}"
@@ -221,6 +221,11 @@
 		{202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
 	EndProjectSection
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cdr", "..\..\src\mod\event_handlers\mod_cdr\mod_cdr.vcproj", "{3D1EED36-A510-4EDB-B4D9-4E0F4A5EC2A8}"
+	ProjectSection(ProjectDependencies) = postProject
+		{202D7A4E-760D-4D0E-AFA1-D7459CED30FF} = {202D7A4E-760D-4D0E-AFA1-D7459CED30FF}
+	EndProjectSection
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -379,6 +384,10 @@
 		{05515420-16DE-4E63-BE73-85BE85BA5142}.Debug|Win32.Build.0 = Debug|Win32
 		{05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.ActiveCfg = Release|Win32
 		{05515420-16DE-4E63-BE73-85BE85BA5142}.Release|Win32.Build.0 = Release|Win32
+		{3D1EED36-A510-4EDB-B4D9-4E0F4A5EC2A8}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3D1EED36-A510-4EDB-B4D9-4E0F4A5EC2A8}.Debug|Win32.Build.0 = Debug|Win32
+		{3D1EED36-A510-4EDB-B4D9-4E0F4A5EC2A8}.Release|Win32.ActiveCfg = Release|Win32
+		{3D1EED36-A510-4EDB-B4D9-4E0F4A5EC2A8}.Release|Win32.Build.0 = Release|Win32
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -395,6 +404,7 @@
 		{C7705DC4-2088-493E-AF8D-65BC6D65C125} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
 		{784113EF-44D9-4949-835D-7065D3C7AD08} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
 		{05515420-16DE-4E63-BE73-85BE85BA5142} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
+		{3D1EED36-A510-4EDB-B4D9-4E0F4A5EC2A8} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0}
 		{AFAC0568-7548-42D5-9F6A-8D3400A1E4F6} = {A5A27244-AD24-46E5-B01B-840CD296C91D}
 		{78100236-7CEA-4948-96CC-E8ED3160329C} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}
 		{E1794405-29D4-466D-9BE3-DD2344C2A663} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78}



More information about the Freeswitch-svn mailing list