2006-07-24 15:19:05 +00:00
/*
* 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 ) ;
2006-12-07 04:15:38 +00:00
memset ( formattedcalltransferdate , 0 , 100 ) ;
2006-07-24 15:19:05 +00:00
memset ( formattedcallenddate , 0 , 100 ) ;
if ( newchannel ! = 0 )
{
2006-12-07 04:15:38 +00:00
switch_time_exp_t tempcallstart , tempcallanswer , tempcalltransfer , tempcallend ;
2006-07-24 15:19:05 +00:00
memset ( & tempcallstart , 0 , sizeof ( tempcallstart ) ) ;
2006-12-07 04:15:38 +00:00
memset ( & tempcalltransfer , 0 , sizeof ( tempcalltransfer ) ) ;
2006-07-24 15:19:05 +00:00
memset ( & tempcallanswer , 0 , sizeof ( tempcallanswer ) ) ;
memset ( & tempcallend , 0 , sizeof ( tempcallend ) ) ;
2006-12-07 04:15:38 +00:00
convert_time ( & tempcallstart , callstartdate ) ;
convert_time ( & tempcallanswer , callanswerdate ) ;
convert_time ( & tempcalltransfer , calltransferdate ) ;
convert_time ( & tempcallend , callenddate ) ;
2006-07-24 15:19:05 +00:00
// Format the times
2007-03-09 20:44:13 +00:00
switch_size_t retsizecsd , retsizecad , retsizectd , retsizeced ; //csd == callstartdate, cad == callanswerdate, ced == callenddate, ceff == callenddate_forfile
2006-12-07 04:15:38 +00:00
char format [ ] = " %Y-%m-%d %H:%M:%S " ;
2006-07-24 15:19:05 +00:00
switch_strftime ( formattedcallstartdate , & retsizecsd , sizeof ( formattedcallstartdate ) , format , & tempcallstart ) ;
switch_strftime ( formattedcallanswerdate , & retsizecad , sizeof ( formattedcallanswerdate ) , format , & tempcallanswer ) ;
2006-12-07 04:15:38 +00:00
switch_strftime ( formattedcalltransferdate , & retsizectd , sizeof ( formattedcalltransferdate ) , format , & tempcalltransfer ) ;
2006-07-24 15:19:05 +00:00
switch_strftime ( formattedcallenddate , & retsizeced , sizeof ( formattedcallenddate ) , format , & tempcallend ) ;
2007-01-22 23:33:35 +00:00
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 ) ;
2006-07-24 15:19:05 +00:00
}
}
CsvCDR : : ~ CsvCDR ( )
{
}
bool CsvCDR : : activated = 0 ;
bool CsvCDR : : logchanvars = 0 ;
bool CsvCDR : : connectionstate = 0 ;
bool CsvCDR : : repeat_fixed_in_supp = 0 ;
2006-12-07 04:15:38 +00:00
modcdr_time_convert_t CsvCDR : : convert_time = switch_time_exp_lt ;
2006-07-24 15:19:05 +00:00
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 ;
2006-12-07 04:15:38 +00:00
std : : string CsvCDR : : display_name = " CsvCDR - The simple comma separated values CDR logger " ;
2006-07-24 15:19:05 +00:00
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 ;
}
}
2006-12-07 04:15:38 +00:00
else if ( ! strcmp ( var , " timezone " ) )
{
if ( ! strcmp ( val , " utc " ) )
convert_time = switch_time_exp_gmt ;
else if ( ! strcmp ( val , " local " ) )
convert_time = switch_time_exp_lt ;
else
{
switch_console_printf ( SWITCH_CHANNEL_LOG , " Invalid configuration parameter for timezone. Possible values are utc and local. You entered: %s \n Defaulting to local. \n " , val ) ;
convert_time = switch_time_exp_lt ;
}
}
2006-07-24 15:19:05 +00:00
}
if ( count_config_params > 0 )
{
open_file ( ) ;
if ( outputfile . good ( ) )
{
activated = 1 ;
2007-02-14 20:15:51 +00:00
switch_console_printf ( SWITCH_CHANNEL_LOG , " CsvCDR activated, log rotation will occur at or after %d MB \n " , ( int ) ( filesize_limit > > 20 ) ) ;
2006-07-24 15:19:05 +00:00
}
}
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 ) ;
2007-03-09 20:44:13 +00:00
switch_size_t retsize ;
2006-08-13 04:41:40 +00:00
char format [ ] = " %Y-%m-%d-%H-%M-%S " ;
2006-07-24 15:19:05 +00:00
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 ;
}
2007-01-22 22:03:56 +00:00
else
{
outputfile < < " callstartdate,formattedcallstartdate,callanswerdate,formattedcallanswerdate,calltransferdate,formattedcalltransferdate,callendate,formattedcallenddate,hangupcause_text,hangupcause,clid,originated,dialplan,myuuid,destuuid,src,dst,srcchannel,dstchannel,ani,aniii,network_address,lastapp,lastdata,billusec,disposition,amaflags " ;
if ( chanvars_fixed_list . size ( ) )
{
std : : list < std : : string > : : iterator iItr , iEnd ;
for ( iItr = chanvars_fixed_list . begin ( ) , iEnd = chanvars_fixed_list . end ( ) ; iItr ! = iEnd ; iItr + + )
outputfile < < " , " < < * iItr ;
}
2006-07-24 15:19:05 +00:00
2007-01-22 22:03:56 +00:00
if ( logchanvars )
outputfile < < " ,chanvars_supp " ;
outputfile < < std : : endl ;
}
2006-07-24 15:19:05 +00:00
}
bool CsvCDR : : process_record ( )
{
check_file_size_and_open ( ) ;
bool retval = 0 ;
// Format the call record and proceed from here...
outputfile < < " \" " < < callstartdate < < " \" , \" " ;
2006-12-07 04:15:38 +00:00
outputfile < < formattedcallstartdate < < " \" , \" " ;
2006-07-24 15:19:05 +00:00
outputfile < < callanswerdate < < " \" , \" " ;
2006-12-07 04:15:38 +00:00
outputfile < < formattedcallanswerdate < < " \" , \" " ;
outputfile < < calltransferdate < < " \" , \" " ;
outputfile < < formattedcalltransferdate < < " \" , \" " ;
2006-07-24 15:19:05 +00:00
outputfile < < callenddate < < " \" , \" " ;
2006-12-07 04:15:38 +00:00
outputfile < < formattedcallenddate < < " \" , \" " ;
2006-07-24 15:19:05 +00:00
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 < < " \" , \" " ;
2006-10-18 18:29:29 +00:00
outputfile < < aniii < < " \" , \" " ;
2006-07-24 15:19:05 +00:00
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 ( )
{
}
2006-12-07 04:15:38 +00:00
std : : string CsvCDR : : get_display_name ( )
{
return display_name ;
}
2006-07-24 15:19:05 +00:00
void CsvCDR : : disconnect ( )
{
outputfile . close ( ) ;
2006-12-07 04:15:38 +00:00
activated = 0 ;
logchanvars = 0 ;
repeat_fixed_in_supp = 0 ;
outputfile_path . clear ( ) ;
chanvars_fixed_list . clear ( ) ;
chanvars_supp_list . clear ( ) ;
connectionstate = 0 ;
2007-01-22 22:03:56 +00:00
switch_console_printf ( SWITCH_CHANNEL_LOG , " Shutting down CsvCDR... Done! \n " ) ;
2006-07-24 15:19:05 +00:00
}
AUTO_REGISTER_BASECDR ( CsvCDR ) ;
2006-11-27 22:30:48 +00:00
/* For Emacs:
* Local Variables :
2006-12-07 04:15:38 +00:00
* mode : c + +
2007-02-09 02:36:03 +00:00
* indent - tabs - mode : t
2006-11-27 22:30:48 +00:00
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 expandtab :
*/