/* * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application Call Detail Recorder module * Copyright 2006, Author: Yossi Neiman of Cartis Solutions, Inc. * * 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 * Portions created by the Initial Developer are Copyright (C) * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Yossi Neiman * * 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 #include #include #include 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) { errorstate = 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," <",2); if(newchannel->callerprofile->caller_id_number != 0 ) strncat(clid,newchannel->callerprofile->caller_id_number,strlen(clid)+strlen(newchannel->callerprofile->caller_id_number)); strncat(clid,">",1); } // 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)); 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); 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; } } 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& 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::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& chanvarlist,std::vector& 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 tempchanvarlist; // = chanvarlist; std::list::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& stringlist,switch_channel_t *channel) { std::list::const_iterator iItr,iEnd; iEnd = stringlist.end(); for(iItr = stringlist.begin(); iItr != iEnd; iItr++) { std::vector tempstringvector(iItr->begin(), iItr->end()); tempstringvector.push_back('\0'); char* tempstring= &tempstringvector[0]; char *tempvariable; tempvariable = switch_channel_get_variable(channel,tempstring); std::pair 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& stringlist, const std::list& 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::const_iterator iItr,iEnd; iEnd = stringlist.end(); for(iItr = stringlist.begin(); iItr != iEnd; iItr++) { std::vector 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::iterator MapItr; std::list::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); } } }