CSTA interface added
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/Download CSTAInside.vcproj (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/Download CSTAInside.vcproj 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="Download CSTAInside"
+ ProjectGUID="{4F92B672-DADB-4047-8D6A-4BB3796733FD}"
+ RootNamespace="Download CSTAInside"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="10"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog $(ProjectName).htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ Description="Downloading CSTAInside"
+ CommandLine="if not exist "$(ProjectDir)CSTAInsideCore" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://freefr.dl.sourceforge.net/project/cstainside/cstainside/v0.2.0/cstainside_v0.2.0.92.zip "$(ProjectDir).""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ CommandLine=""
+ Outputs=""
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if exist cstainside_v0.2.0.92 ren cstainside_v0.2.0.92 CSTAInsideCore"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="10"
+ CharacterSet="2"
+ BuildLogFile="$(IntDir)\BuildLog $(ProjectName).htm"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ Description="Downloading CSTAInside"
+ CommandLine="if not exist "$(ProjectDir)CSTAInsideCore" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://freefr.dl.sourceforge.net/project/cstainside/cstainside/v0.2.0/cstainside_v0.2.0.92.zip "$(ProjectDir).""
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if exist cstainside_v0.2.0.92 ren cstainside_v0.2.0.92 CSTAInsideCore"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\cleancount"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Downloading CSTAInsideCore."
+ CommandLine="if not exist "$(ProjectDir)CSTAInsideCore" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://freefr.dl.sourceforge.net/project/cstainside/cstainside/v0.2.0/cstainside_v0.2.0.92.zip "$(ProjectDir)."
"
+ Outputs="$(ProjectDir)."
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCustomBuildTool"
+ Description="Downloading CSTAInsideCore."
+ CommandLine="if not exist "$(ProjectDir)CSTAInsideCore" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://freefr.dl.sourceforge.net/project/cstainside/cstainside/v0.2.0/cstainside_v0.2.0.92.zip "$(ProjectDir)."
"
+ Outputs="$(ProjectDir)."
+ />
+ </FileConfiguration>
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCH.cpp (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCH.cpp 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,1737 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+#include <switch.h>
+#include <direct.h>
+#include "FreeSWITCH.h"
+
+#include "MonitorStartRequest.h"
+#include "UniversalErrorResponse.h"
+#include "MonitorStartResponse.h"
+#include "MakeCallRequest.h"
+#include "MakeCallResponse.h"
+#include "AnswerCallRequest.h"
+#include "AnswerCallResponse.h"
+#include "SingleStepTransferCallRequest.h"
+#include "SingleStepTransferCallResponse.h"
+#include "DeflectCallRequest.h"
+#include "DeflectCallResponse.h"
+#include "PlayMessageRequest.h"
+#include "PlayMessageResponse.h"
+#include "RecordMessageRequest.h"
+#include "RecordMessageResponse.h"
+#include "StopRequest.h"
+#include "StopResponse.h"
+#include "ServiceInitiatedEvent.h"
+#include "OriginatedEvent.h"
+#include "DeliveredEvent.h"
+#include "EstablishedEvent.h"
+#include "ConnectionClearedEvent.h"
+#include "QueuedEvent.h"
+#include "DtmfDetectedEvent.h"
+#include "PlayEvent.h"
+#include "RecordEvent.h"
+#include "StopEvent.h"
+#include "ClearConnectionRequest.h"
+#include "ClearConnectionResponse.h"
+#include "SnapshotDeviceRequest.h"
+#include "SnapshotDeviceResponse.h"
+#include "SnapshotCallRequest.h"
+#include "SnapshotCallResponse.h"
+
+#include <string>
+using namespace std;
+
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// class FreeSwitchDevice
+
+/*static*/ std::string FreeSwitchDevice::Channel2Device(const char* channel)
+{
+ string strDevice;
+ if(strncmp(channel, "sofia/internal/", 15)==0)
+ {
+ if(strncmp(channel+15, "sip:", 4)==0)
+ strDevice=channel+19;
+ else
+ strDevice=channel+15;
+ }
+ std::string::size_type i=strDevice.find("@");
+ if(i!=strDevice.npos)
+ {
+ strDevice.erase(i);
+ }
+
+ return strDevice;
+}
+
+/*static*/ char * FreeSwitchDevice::Type2Prefix(FreeSwitchDeviceType type)
+{
+ switch(type)
+ {
+ case type_network_interface: return "01";
+ case type_queue: return "02";
+ default: return "";
+ };
+}
+
+/*static*/ FreeSwitchDeviceType FreeSwitchDevice::Device2Type(DeviceID device)
+{
+ if(device.GetTypeOfNumber()==typeOfNumberDialable)
+ return type_internal_subscriber;
+
+ if(device.GetCallNr().size()<2)
+ return type_unknown;
+
+ for(int i=type_network_interface;Type2Prefix((FreeSwitchDeviceType)i)[0]!=0;i++)
+ {
+ if(strncmp(Type2Prefix((FreeSwitchDeviceType)i),device.GetCallNr().c_str(),2)==0)
+ {
+ return (FreeSwitchDeviceType)i;
+ }
+ }
+
+ return type_unknown;
+}
+
+
+FreeSwitchDevice::FreeSwitchDevice(const char* pcDevice, FreeSwitchDeviceType deviceType/*=type_internal_subscriber*/) : m_strDevice(pcDevice), m_deviceType(deviceType), m_bIsMakeCallOriginator(false)
+{
+
+}
+
+FreeSwitchConnection* FreeSwitchDevice::FindConnection(const char* uuid)
+{
+ for(MapCall2Connection::iterator it=connections.begin();it!=connections.end();it++)
+ {
+ if(it->first->strUUID==uuid)
+ return it->second;
+ }
+ return NULL;
+}
+
+FreeSwitchConnection* FreeSwitchDevice::FindConnection(FreeSwitchCall* pCall)
+{
+ MapCall2Connection::iterator it=connections.find(pCall);
+ if(it==connections.end())
+ return NULL;
+ else
+ return it->second;
+}
+
+FreeSwitchConnection* FreeSwitchDevice::AddConnection(const char* uuid, const char * channel, FreeSwitchCall* pCall, eDirection direction)
+{
+ FreeSwitchConnection* pConnection=new FreeSwitchConnection();
+ pConnection->pCall=pCall;
+ pConnection->strUUID=uuid;
+ pConnection->state=STATE_INITIATED;
+ pConnection->direction=direction;
+ pConnection->strChannel=channel;
+ pCall->devices[GetDeviceID()]=this;
+ connections[pCall]=pConnection;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSwitchDevice::AddConnection: connection %s - %s added.\n",this->m_strDevice.c_str(),pCall->strUUID.c_str());
+
+ return pConnection;
+}
+
+void FreeSwitchDevice::DeleteConnection(FreeSwitchCall* pCall)
+{
+ MapCall2Connection::iterator it=connections.find(pCall);
+ if(it==connections.end())
+ return;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSwitchDevice::DeleteConnection: connection %s - %s deleted.\n",this->m_strDevice.c_str(),pCall->strUUID.c_str());
+
+ delete it->second;
+ connections.erase(it);
+
+ pCall->devices.erase(this->GetDeviceID());
+}
+
+
+bool FreeSwitchDevice::IsMonitoredWithID(string crossRefID)
+{
+ return m_MonitoringSessions.find(crossRefID)==m_MonitoringSessions.end()?false:true;
+}
+
+bool FreeSwitchDevice::AddMonitor(CISession* session, string crossRefID)
+{
+ if(IsMonitoredWithID(crossRefID))
+ return false; //XRefID already used
+
+ m_MonitoringSessions[crossRefID]=session;
+ return true;
+}
+
+bool FreeSwitchDevice::RemoveMonitor(CISession* session)
+{
+ bool found=false;
+ for(MapStr2Session::iterator it=m_MonitoringSessions.begin();it!=m_MonitoringSessions.end();it++)
+ if(it->second==session)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSwitchDevice::RemoveMonitor: removing session 0x%08X from device %s\n",session, m_strDevice.c_str());
+ it=m_MonitoringSessions.erase(it);
+ found=true;
+ if(it==m_MonitoringSessions.end())
+ break;
+ }
+ return found;
+}
+
+bool FreeSwitchDevice::RemoveMonitor(CISession* session, string crossRefID)
+{
+ MapStr2Session::iterator it=m_MonitoringSessions.find(crossRefID);
+
+ if(it==m_MonitoringSessions.end())
+ return false; //XRefID not found
+
+ if(it->second!=session)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSwitchDevice::RemoveMonitor: XRefID %s mapped to device %sbut from session 0x%08X instead of 0x%08X, removal denied.\n",crossRefID.c_str(), m_strDevice.c_str(), it->second, session);
+ }
+ m_MonitoringSessions.erase(it);
+ return true;
+}
+
+void FreeSwitchDevice::SendEvent(CSTAEvent* pEvent)
+{
+ for(MapStr2Session::iterator it=m_MonitoringSessions.begin();it!=m_MonitoringSessions.end();it++)
+ {
+ pEvent->SetCrossRefID(it->first);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSwitchDevice::SendEvent: device %s, session %X, sending event: \n%s\n",GetDeviceID().c_str(),it->second,pEvent->GetReadable().c_str());
+ it->second->SendMsg(pEvent);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// class FreeSwitchCall
+
+FreeSwitchDevice* FreeSwitchCall::GetDevice(std::string strDeviceID)
+{
+ MapStr2Device::iterator it=devices.find(strDeviceID);
+ if(it!=devices.end())
+ return it->second;
+ else
+ return NULL;
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// class FreeSwitch
+
+FreeSWITCH::FreeSWITCH(switch_memory_pool_t *pool) : m_pool(pool), m_nLastXRefID(0)
+{
+ switch_mutex_init(&m_mutex, SWITCH_MUTEX_NESTED, m_pool);
+}
+
+
+FreeSWITCH::~FreeSWITCH()
+{
+ for(MapStr2Device::iterator it=m_DeviceMap.begin();it!=m_DeviceMap.end();it++)
+ {
+ delete it->second;
+ }
+ m_DeviceMap.clear();
+ switch_mutex_destroy(m_mutex);
+}
+
+string FreeSWITCH::GetNextXRefID()
+{
+ ++m_nLastXRefID;
+ if(m_nLastXRefID>100000)
+ m_nLastXRefID=1;
+ char temp[8];
+ itoa(m_nLastXRefID,temp,10);
+ return string(temp);
+}
+
+
+FreeSwitchDevice * FreeSWITCH::PrepareDevice(const char * pcDevice, FreeSwitchDeviceType type/*=type_internal_subscriber*/)
+{
+ string strFullDevName=FreeSwitchDevice::Type2Prefix(type);
+ strFullDevName+=pcDevice;
+
+ MapStr2Device::iterator it=m_DeviceMap.find(strFullDevName);
+ FreeSwitchDevice* pDevice=NULL;
+ if(it==m_DeviceMap.end())
+ {
+ pDevice=new FreeSwitchDevice(strFullDevName.c_str(),type);
+ m_DeviceMap[strFullDevName]=pDevice;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PrepareDevice: device %s type %d added.", pcDevice, type);
+ }
+ else
+ {
+ pDevice=it->second;
+ if(pDevice->GetDeviceType()!=type)
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PrepareDevice: device %s found but type is different!",pcDevice);
+
+ }
+
+ return pDevice;
+}
+
+FreeSwitchCall* FreeSWITCH::GetCall(const char * pcUUID)
+{
+ if(!pcUUID)
+ return NULL;
+ MapStr2Call::iterator it=m_CallMap.find(pcUUID);
+ if(it==m_CallMap.end())
+ return NULL;
+ else return it->second; //TODO: might chech the secondary UUID
+}
+
+bool FreeSWITCH::IsXRefIDUsed(string crossRefID)
+{
+ switch_mutex_lock(m_mutex);
+
+ for(MapStr2Device::iterator it=m_DeviceMap.begin();it!=m_DeviceMap.end();it++)
+ {
+ if(it->second->IsMonitoredWithID(crossRefID))
+ {
+ switch_mutex_unlock(m_mutex);
+ return true;
+ }
+ }
+
+ switch_mutex_unlock(m_mutex);
+ return false;
+}
+
+bool FreeSWITCH::FindCallerCalled(const char* uuid, string* pstrCaller, string* pstrCalled)
+{
+ switch_core_session_t * session=NULL;
+ for(int i=0;i<3;i++)
+ {
+ session=switch_core_session_locate(uuid);
+ if(session)
+ break;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "FreeSWITCH::FindCallerCalled: Session %s not available, waiting.\n",uuid);
+ switch_yield(100000);
+ }
+
+ if(!session)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::FindCallerCalled: Session %s no longer exists.\n",uuid);
+ return false;
+ }
+ switch_channel_t* channel=switch_core_session_get_channel(session);
+ switch_caller_profile_t * caller=switch_channel_get_caller_profile(channel);
+
+ if(pstrCaller)
+ *pstrCaller=caller->caller_id_number;
+
+ if(pstrCalled)
+ {
+ if(strncmp(caller->destination_number, "sip:", 4)==0)
+ *pstrCalled=caller->destination_number+4;
+ else
+ *pstrCalled=caller->destination_number;
+
+ std::string::size_type i=(*pstrCalled).find("@");
+ if(i!=(*pstrCalled).npos)
+ {
+ (*pstrCalled).erase(i);
+ }
+ }
+
+ switch_core_session_rwunlock(session);
+ return true;
+}
+
+bool FreeSWITCH::PrepareCallData(const char* uuid, const char* uuid2, const char* channel, FreeSwitchDevice** ppDevice, FreeSwitchCall** ppCall, FreeSwitchConnection** ppConnection, bool bCreateCall, FreeSwitchDevice** ppQueue, FreeSwitchDevice** ppInboundNID, FreeSwitchDevice** ppOutboundNID, string* pstrCaller, string* pstrCalled)
+{
+ if(!ppDevice || !ppCall)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PrepareCallData: mandatory parameter is null.\n");
+ return false;
+ }
+
+ //Finding call:
+ if( !(*ppCall=GetCall(uuid)) && !(uuid2 && (*ppCall=GetCall(uuid2))) )
+ {
+ if(!bCreateCall)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "FreeSWITCH::PrepareCallData: call %s [or %s] not found.\n",uuid, uuid2?uuid2:"NULL");
+ return false;
+ }
+
+ *ppCall=new FreeSwitchCall();
+ (*ppCall)->strUUID=uuid;
+ m_CallMap[(*ppCall)->strUUID]=*ppCall;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PrepareCallData: call %s created.\n",(*ppCall)->strUUID.c_str());
+ }
+
+ //Finding the subscriber:
+ if(strncmp(channel,"sofia/external",14)==0)
+ {
+ //Network interface - finding later
+ *ppDevice=NULL;
+ }
+ else
+ {
+ //Internal subscriber
+ string device=FreeSwitchDevice::Channel2Device(channel);
+ if(!device.size())
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PrepareCallData: Channel %s not recognized.\n",channel);
+ return false;
+ }
+ *ppDevice=PrepareDevice(device.c_str());
+ if(!(*ppDevice))
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PrepareCallData: Device %s not recognized.\n",device.c_str());
+ return false;
+ }
+ }
+ if(!*ppDevice || ppQueue || ppInboundNID || ppOutboundNID)
+ {
+
+ //Collecting special devices from the call & finding network subscriber:
+ for(MapStr2Device::iterator it=(*ppCall)->devices.begin();it!=(*ppCall)->devices.end();it++)
+ {
+ if(ppQueue && it->second->GetDeviceType()==type_queue)
+ {
+ *ppQueue=it->second;
+ }
+ else
+ if(it->second->GetDeviceType()==type_network_interface)
+ {
+ FreeSwitchConnection* pTempConn=it->second->FindConnection(*ppCall);
+ if(!pTempConn)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "FreeSWITCH::PrepareCallData: trunk %s is mapped to call %s without connection????\n",it->second->GetDeviceID().c_str(),(*ppCall)->strUUID.c_str());
+ continue;
+ }
+ if(ppInboundNID && pTempConn->direction==direction_incoming)
+ *ppInboundNID=it->second;
+ else
+ if(ppOutboundNID && pTempConn->direction==direction_outgoing)
+ *ppOutboundNID=it->second;
+
+ if( (!*ppDevice) && (pTempConn->strChannel==channel) )
+ *ppDevice=it->second;
+
+ if( (!*ppDevice) && (pTempConn->strChannel.size()==0) && (pTempConn->direction==direction_outgoing) )
+ {
+ //External outbound call: the device was created before the FS channel, updating the data.
+ *ppDevice=it->second;
+ pTempConn->strUUID=uuid;
+ pTempConn->strChannel=channel;
+ }
+ }
+ }
+ }
+
+ if(!*ppDevice)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PrepareCallData: Device for channel %s not recognized.\n",channel);
+ return false;
+ }
+
+ //Finding connection:
+ if(ppConnection)
+ *ppConnection=(*ppDevice)->FindConnection(*ppCall);
+
+
+ //Finding caller & called
+ if(pstrCaller || pstrCalled)
+ {
+ FindCallerCalled(uuid, pstrCaller, pstrCalled);
+ }
+
+ return true;
+}
+
+
+
+void FreeSWITCH::OnChannelCreate(switch_event_t *event)
+{
+ const char* channel=switch_event_get_header(event, "Channel-Name");
+ if(!channel || strstr(channel,"sofia/external")) //External inbound calls are handled in OnCallNetworkIncoming
+ return;
+
+ string device=FreeSwitchDevice::Channel2Device(channel);
+ if(!device.size())
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnChannelCreate: Channel %s not recognized.\n",channel);
+ return;
+ }
+ switch_mutex_lock(m_mutex);
+ FreeSwitchDevice* pDevice=PrepareDevice(device.c_str());
+ if(!pDevice)
+ return;
+ const char* direction=switch_event_get_header(event, "Call-Direction");
+ const char* uuid=switch_event_get_header(event, "Unique-ID");
+ if( !direction || !uuid
+ || (strcmp(direction, "inbound") && !pDevice->IsMakeCallOriginator()) ) //direction= "inbound" means outgoing call, direction is wrong from some reason
+ {
+ switch_mutex_unlock(m_mutex);
+ return;
+ }
+
+ if(GetCall(uuid))
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnChannelCreate: Call %s already exists.\n",uuid);
+ switch_mutex_unlock(m_mutex);
+ return;
+ }
+
+ FreeSwitchCall* pCall=new FreeSwitchCall();
+ pCall->strUUID=uuid;
+ m_CallMap[pCall->strUUID]=pCall;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnChannelCreate: call %s created.\n",pCall->strUUID.c_str());
+
+ pDevice->AddConnection(uuid, switch_event_get_header(event, "Channel-Name"), pCall,direction_outgoing);
+ if(pDevice->IsMonitored())
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnChannelCreate: ServiceInitiated device: %s, call: %s.\n",pDevice->GetDeviceID().c_str(),uuid);
+ ServiceInitiatedEvent si(ConnectionID(pDevice->GetDeviceID(),pCall->strUUID));
+ if(pDevice->IsMakeCallOriginator())
+ si.SetEventCause(CAUSE_MAKE_CALL);
+ pDevice->SendEvent(&si);
+ }
+ switch_mutex_unlock(m_mutex);
+}
+
+
+void FreeSWITCH::OnProgress(switch_event_t *event)
+{
+ const char* channel=switch_event_get_header(event, "Channel-Name");
+ const char* uuid=switch_event_get_header(event, "Unique-ID");
+ const char* uuid2=switch_event_get_header(event, "Other-Leg-Unique-ID");
+ if(!channel || !uuid)
+ return;
+
+ FreeSwitchCall* pCall;
+ FreeSwitchDevice* pDevice=NULL, *pInboundNIDDevice=NULL, *pOutboundNIDDevice=NULL;
+ string caller, called;
+ FreeSwitchConnection* pConnection=NULL;
+
+ switch_mutex_lock(m_mutex);
+ if(!PrepareCallData(uuid, uuid2, channel, &pDevice, &pCall, &pConnection, true, NULL, &pInboundNIDDevice, &pOutboundNIDDevice, &caller, &called))
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnProgress: PrepareCallData failed.\n");
+ return;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnProgress: %s device: %s, call: %s [%s].\n",event->event_id==SWITCH_EVENT_CHANNEL_PROGRESS?"CHANNEL_PROGRESS":"CHANNEL_PROGRESS_MEDIA",pDevice->GetDeviceID().c_str(), uuid, uuid2?uuid2:"NULL");
+
+ if(!pConnection)
+ {
+ pConnection=pDevice->AddConnection(uuid,channel,pCall,direction_incoming);
+ pConnection->state=STATE_ALERTING;
+ }
+ else
+ pConnection->state=STATE_CONNECTED;
+
+ DeviceID alertingDevice(called);
+
+ OriginatedEvent oe(ConnectionID(caller,pCall->strUUID), caller, called);
+ oe.SetLocalConnectionInfo(STATE_CONNECTED);
+ DeliveredEvent de(ConnectionID(alertingDevice,pCall->strUUID), alertingDevice, caller, called);
+ de.SetLocalConnectionInfo(pConnection->state);
+
+ if(pInboundNIDDevice)
+ {
+ oe.SetNetworkCalledDevice(called);
+ oe.SetNetworkCallingDevice(caller);
+ oe.SetAssociatedCallingDevice(DeviceID(typeOfNumberDevice,pInboundNIDDevice->GetDeviceID()));
+
+ de.SetNetworkCalledDevice(called);
+ de.SetNetworkCallingDevice(caller);
+ de.SetAssociatedCallingDevice(DeviceID(typeOfNumberDevice,pInboundNIDDevice->GetDeviceID()));
+ }
+ if(pOutboundNIDDevice)
+ {
+ de.SetAssociatedCalledDevice(DeviceID(typeOfNumberDevice,pOutboundNIDDevice->GetDeviceID()));
+ de.SetConnection(ConnectionID(DeviceID(typeOfNumberDevice,pOutboundNIDDevice->GetDeviceID()),pCall->strUUID));
+ }
+
+ if(pDevice->IsMonitored())
+ {
+ if(pConnection->state==STATE_CONNECTED)
+ pDevice->SendEvent(&oe);
+ pDevice->SendEvent(&de);
+ }
+
+ switch_mutex_unlock(m_mutex);
+}
+
+
+void FreeSWITCH::OnChannelAnswer(switch_event_t *event)
+{
+ const char* channel=switch_event_get_header(event, "Channel-Name");
+ const char* uuid=switch_event_get_header(event, "Unique-ID");
+ const char* uuid2=switch_event_get_header(event, "Other-Leg-Unique-ID");
+ if(!channel || !uuid)
+ return;
+
+ FreeSwitchCall* pCall;
+ FreeSwitchDevice* pDevice=NULL, *pQueueDevice=NULL, *pInboundNIDDevice=NULL, *pOutboundNIDDevice=NULL;
+ string caller, called;
+ FreeSwitchConnection* pConnection=NULL;
+
+ switch_mutex_lock(m_mutex);
+ if(!PrepareCallData(uuid, uuid2, channel, &pDevice, &pCall, &pConnection, true, &pQueueDevice, &pInboundNIDDevice, &pOutboundNIDDevice, &caller, &called))
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnChannelAnswer: PrepareCallData failed.\n");
+ return;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnChannelAnswer: CHANNEL_ANSWER device: %s, call: %s [%s].\n",pDevice->GetDeviceID().c_str(), uuid, uuid2?uuid2:"NULL");
+
+ if(!pConnection)
+ {
+ pConnection=pDevice->AddConnection(uuid,channel,pCall,direction_incoming);
+ }
+
+ pConnection->state=STATE_CONNECTED;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnChannelAnswer: Established device: %s, call: %s.\n",pDevice->GetDeviceID().c_str(),pCall->strUUID.c_str());
+
+ DeviceID answeringDevice;
+ if(pQueueDevice)
+ {
+ answeringDevice.SetCallNr(pQueueDevice->GetDeviceID().c_str());
+ answeringDevice.SetTypeOfNumber(typeOfNumberDevice);
+ }
+ else
+ {
+ answeringDevice.SetCallNr(called);
+ }
+ EstablishedEvent ee(ConnectionID(answeringDevice,pCall->strUUID), answeringDevice, caller, called);
+
+ if(pInboundNIDDevice)
+ {
+ ee.SetNetworkCalledDevice(called);
+ ee.SetNetworkCallingDevice(caller);
+ ee.SetAssociatedCallingDevice(DeviceID(typeOfNumberDevice,pInboundNIDDevice->GetDeviceID()));
+ }
+ if(pOutboundNIDDevice)
+ {
+ ee.SetAssociatedCalledDevice(DeviceID(typeOfNumberDevice,pOutboundNIDDevice->GetDeviceID()));
+ ee.SetEstablishedConnection(ConnectionID(DeviceID(typeOfNumberDevice,pOutboundNIDDevice->GetDeviceID()),pCall->strUUID));
+ }
+
+ if(pDevice->IsMonitored())
+ pDevice->SendEvent(&ee);
+
+ if(pQueueDevice && pQueueDevice->IsMonitored())
+ pQueueDevice->SendEvent(&ee);
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::OnChannelHangup(switch_event_t *event)
+{
+ char* channel=switch_event_get_header(event, "Channel-Name");
+ const char* uuid=switch_event_get_header(event, "Unique-ID");
+ const char* uuid2=switch_event_get_header(event, "Other-Leg-Unique-ID");
+ const char* cause=switch_event_get_header(event, "Hangup-Cause");
+ if(!channel || !uuid)
+ return;
+
+ FreeSwitchCall* pCall=NULL;
+ FreeSwitchDevice* pDevice=NULL, *pQueueDevice=NULL;
+
+ switch_mutex_lock(m_mutex);
+ if(!PrepareCallData(uuid, uuid2, channel, &pDevice, &pCall, NULL, false, NULL, NULL, NULL, NULL, NULL))
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnChannelHangup: PrepareCallData failed.\n");
+ return;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnChannelHangup: CHANNEL_HANGUP device: %s, call: %s [%s], cause: %s.\n",pDevice->GetDeviceID().c_str(),uuid, uuid2?uuid2:"NULL", cause?cause:"NULL");
+
+ ConnectionClearedEvent cc(ConnectionID(pDevice->GetDeviceID(),pCall->strUUID));
+
+ //Setting cause
+ if(!cause || !strcmp(cause,"NORMAL_CLEARING") )
+ cc.SetEventCause(CAUSE_NORMAL_CLEARING);
+ else
+ if(!strcmp(cause,"NO_ROUTE_DESTINATION"))
+ cc.SetEventCause(CAUSE_DEST_NOT_OBTAINABLE);
+ else
+ if(!strcmp(cause,"USER_BUSY"))
+ cc.SetEventCause(CAUSE_BUSY);
+ if(!strcmp(cause,"ORIGINATOR_CANCEL"))
+ cc.SetEventCause(CAUSE_CALL_NOT_ANSWERED);
+
+ int devices_in_call=pCall->devices.size();
+ //Sending event to all devices in the call
+ FreeSwitchConnection* pConnection=NULL;
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ {
+ pConnection=it->second->FindConnection(pCall->strUUID.c_str());
+ if(!pConnection)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnChannelHangup: Device %s could not have connection to %s.",it->second->GetDeviceID().c_str(),pCall->strUUID.c_str());
+ continue;
+ }
+
+ if(it->second->GetDeviceType()==type_queue)
+ {
+ pConnection->state=STATE_NULL;
+ pQueueDevice=it->second;
+ }
+ else
+ if(it->second==pDevice)
+ pConnection->state=STATE_NULL; //The terminated device
+ else
+ if(devices_in_call<=2)
+ pConnection->state=STATE_FAIL; //If only one device remain, it will be in failed state
+ //If more than one devices remain (conference), they will have the original state.
+
+ if(it->second->IsMonitored())
+ {
+ cc.SetLocalConnectionInfo(pConnection->state);
+ it->second->SendEvent(&cc);
+ }
+ }
+ pDevice->DeleteConnection(pCall);
+ if(pQueueDevice)
+ {
+ if(pQueueDevice->IsMonitored())
+ {
+ ConnectionClearedEvent cc2(ConnectionID(DeviceID(typeOfNumberDevice,pQueueDevice->GetDeviceID()),pCall->strUUID));
+ cc2.SetLocalConnectionInfo(STATE_NULL);
+ cc2.SetEventCause(cc.GetEventCause());
+ pQueueDevice->SendEvent(&cc2);
+ }
+ pQueueDevice->DeleteConnection(pCall);
+ }
+
+ if(pCall->devices.size()==0)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnChannelHangup: call %s deleted.\n",pCall->strUUID.c_str());
+ m_CallMap.erase(pCall->strUUID);
+ delete pCall;
+ }
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::OnDtmf(switch_event_t *event)
+{
+ char* channel=switch_event_get_header(event, "Channel-Name");
+ const char* uuid=switch_event_get_header(event, "Unique-ID");
+ const char* uuid2=switch_event_get_header(event, "Other-Leg-Unique-ID");
+ if(!channel || !uuid)
+ return;
+
+ FreeSwitchCall* pCall=NULL;
+ FreeSwitchDevice* pDevice=NULL, *pQueueDevice=NULL;
+
+ switch_mutex_lock(m_mutex);
+
+ if(!PrepareCallData(uuid, uuid2, channel, &pDevice, &pCall, NULL, false, &pQueueDevice, NULL, NULL, NULL, NULL))
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnDtmf: PrepareCallData failed.\n");
+ return;
+ }
+
+ const char* digit=switch_event_get_header(event, "DTMF-Digit");
+ if(!digit)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnDtmf: DTMF-Digit not found in event.");
+ switch_mutex_unlock(m_mutex);
+ return;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnDtmf: DTMF device: %s, call: %s \n",pDevice->GetDeviceID().c_str(),pCall->strUUID.c_str());
+
+ DeviceID dev(pDevice->GetDeviceType()==type_internal_subscriber?typeOfNumberDialable:typeOfNumberDevice,pDevice->GetDeviceID());
+ DtmfDetectedEvent dd(ConnectionID(dev,pCall->strUUID),digit[0]);
+
+ if(pDevice->IsMonitored())
+ pDevice->SendEvent(&dd);
+
+ if(pQueueDevice && pQueueDevice->IsMonitored())
+ pQueueDevice->SendEvent(&dd);
+
+ switch_mutex_unlock(m_mutex);
+
+}
+
+void FreeSWITCH::OnPlayback(switch_event_t *event)
+{
+ char* channel=switch_event_get_header(event, "Channel-Name");
+ const char* uuid=switch_event_get_header(event, "Unique-ID");
+ const char* uuid2=switch_event_get_header(event, "Other-Leg-Unique-ID");
+ if(!channel || !uuid)
+ return;
+
+ FreeSwitchCall* pCall=NULL;
+ FreeSwitchDevice* pDevice=NULL;
+
+ switch_mutex_lock(m_mutex);
+
+ if(!PrepareCallData(uuid, uuid2, channel, &pDevice, &pCall, NULL, false, NULL, NULL, NULL, NULL, NULL))
+ {
+ switch_mutex_unlock(m_mutex);
+ if(event->event_id!=SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE) //Could be normal if call terminates during playback.
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnPlayback: PrepareCallData failed.\n");
+ return;
+ }
+
+ const char* file=switch_event_get_header(event, "Application-Data");
+ if(!file)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnPlayback: Filename not found in event.\n");
+ switch_mutex_unlock(m_mutex);
+ return;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnPlayback: device: %s, call: %s \n",pDevice->GetDeviceID().c_str(),pCall->strUUID.c_str());
+
+ DeviceID dev(pDevice->GetDeviceType()==type_internal_subscriber?typeOfNumberDialable:typeOfNumberDevice,pDevice->GetDeviceID());
+
+ CSTAEvent* pEvent=NULL;
+ if(event->event_id==SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE)
+ {
+ pEvent=new StopEvent(ConnectionID(dev,pCall->strUUID),file);
+ char* result=switch_event_get_header(event, "Application-Response");
+ if(result)
+ {
+ if( strcmp(result, "FILE PLAYED")==0)
+ pEvent->SetEventCause(CAUSE_END_OF_MESSAGE_DETECTED);
+ else
+ if(strcmp(result, "FILE NOT FOUND")==0)
+ pEvent->SetEventCause(CAUSE_RESOURCES_NOT_AVAILABLE);
+ else
+ if(strcmp(result, "PLAYBACK ERROR")==0)
+ pEvent->SetEventCause(CAUSE_BLOCKED);
+ }
+ }
+ else
+ {
+ pEvent=new PlayEvent(ConnectionID(dev,pCall->strUUID),file);
+ }
+
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ {
+ if(it->second->IsMonitored())
+ it->second->SendEvent(pEvent);
+ }
+
+ delete pEvent;
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::OnRecord(switch_event_t *event)
+{
+ char* channel=switch_event_get_header(event, "Channel-Name");
+ const char* uuid=switch_event_get_header(event, "Unique-ID");
+ const char* uuid2=switch_event_get_header(event, "Other-Leg-Unique-ID");
+ if(!channel || !uuid)
+ return;
+
+ FreeSwitchCall* pCall=NULL;
+ FreeSwitchDevice* pDevice=NULL;
+
+ switch_mutex_lock(m_mutex);
+
+ if(!PrepareCallData(uuid, uuid2, channel, &pDevice, &pCall, NULL, false, NULL, NULL, NULL, NULL, NULL))
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnRecord: PrepareCallData failed.\n");
+ return;
+ }
+
+ char* p=switch_event_get_header(event, "Application-Data");
+ if(!p)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnRecord: Filename not found in event.\n");
+ switch_mutex_unlock(m_mutex);
+ return;
+ }
+
+ char file[MAX_PATH];
+ strcpy(file,p);
+ p=strstr(file,".wav ");
+ if(p)
+ p[4]=0; //cutting length parameter
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnRecord: device: %s, call: %s \n",pDevice->GetDeviceID().c_str(),pCall->strUUID.c_str());
+
+ DeviceID dev(pDevice->GetDeviceType()==type_internal_subscriber?typeOfNumberDialable:typeOfNumberDevice,pDevice->GetDeviceID());
+
+ CSTAEvent* pEvent=NULL;
+ if(event->event_id==SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE)
+ {
+ pEvent=new StopEvent(ConnectionID(dev,pCall->strUUID),file);
+ pEvent->SetEventCause(CAUSE_MESSAGE_DURATION_EXCEEDED);
+ }
+ else
+ {
+ pEvent=new RecordEvent(ConnectionID(dev,pCall->strUUID),file);
+ }
+
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ {
+ if(it->second->IsMonitored())
+ it->second->SendEvent(pEvent);
+ }
+
+ delete pEvent;
+
+ switch_mutex_unlock(m_mutex);
+}
+
+
+void FreeSWITCH::OnCallQueued(const char* queue, switch_core_session_t *session)
+{
+ const char* uuid=switch_core_session_get_uuid(session);
+ switch_channel_t* channel=switch_core_session_get_channel(session);
+ switch_caller_profile_t * caller=switch_channel_get_caller_profile(channel);
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchDevice* pDevice=PrepareDevice(queue,type_queue);
+ if(!pDevice)
+ return;
+
+ FreeSwitchCall* pCall=GetCall(uuid);
+ if(!pCall)
+ {
+ pCall=new FreeSwitchCall();
+ pCall->strUUID=uuid;
+ m_CallMap[pCall->strUUID]=pCall;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnCallQueued: call %s created.\n",pCall->strUUID.c_str());
+ }
+
+ FreeSwitchConnection* pConnection=pDevice->AddConnection(uuid, switch_channel_get_name(channel),pCall, direction_incoming);
+ pConnection->state=STATE_QUEUED;
+ QueuedEvent qe(ConnectionID(DeviceID(typeOfNumberDevice,pDevice->GetDeviceID()),uuid),DeviceID(typeOfNumberDevice,pDevice->GetDeviceID()),caller->caller_id_number, caller->destination_number);
+
+ if(strstr(caller->chan_name,"sofia/external"))
+ {
+ qe.SetNetworkCallingDevice(caller->caller_id_number);
+ qe.SetNetworkCalledDevice(caller->destination_number);
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ if(it->second->GetDeviceType()==type_network_interface)
+ {
+ qe.SetAssociatedCallingDevice(DeviceID(typeOfNumberDevice,it->second->GetDeviceID()));
+ break;
+ }
+
+ }
+ qe.SetNumberQueued(pDevice->GetConnectionCount());
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ {
+ //Sending queued event for the queue and the caller.
+ if(it->second->IsMonitored())
+ it->second->SendEvent(&qe);
+ }
+
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::OnCallNetworkIncoming(const char* trunk, switch_core_session_t *session)
+{
+ const char* uuid=switch_core_session_get_uuid(session);
+ switch_channel_t* channel=switch_core_session_get_channel(session);
+ //switch_caller_profile_t * caller=switch_channel_get_caller_profile(channel);
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchDevice* pDevice=PrepareDevice(trunk,type_network_interface);
+ if(!pDevice)
+ return;
+
+ FreeSwitchCall* pCall=GetCall(uuid);
+ if(!pCall)
+ {
+ pCall=new FreeSwitchCall();
+ pCall->strUUID=uuid;
+ m_CallMap[pCall->strUUID]=pCall;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnCallNetworkIncoming: call %s created.\n",pCall->strUUID.c_str());
+ }
+
+ FreeSwitchConnection* pConnection=pDevice->AddConnection(uuid, switch_channel_get_name(channel), pCall, direction_incoming);
+ pConnection->strChannel=switch_channel_get_name(channel);
+ if(pDevice->IsMonitored())
+ {
+ ServiceInitiatedEvent si(ConnectionID(DeviceID(typeOfNumberDevice,pDevice->GetDeviceID()),uuid));
+ //TODO: add networkCallingDevice, networkCalledDevice, associatedCallingDevice fields
+ pDevice->SendEvent(&si);
+ }
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::OnCallNetworkOutgoing(const char* trunk, switch_core_session_t *session)
+{
+ const char* uuid=switch_core_session_get_uuid(session);
+ //switch_channel_t* channel=switch_core_session_get_channel(session);
+ //switch_caller_profile_t * caller=switch_channel_get_caller_profile(channel);
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchDevice* pDevice=PrepareDevice(trunk,type_network_interface);
+ if(!pDevice)
+ return;
+
+ FreeSwitchCall* pCall=GetCall(uuid);
+ if(!pCall)
+ {
+ pCall=new FreeSwitchCall();
+ pCall->strUUID=uuid;
+ m_CallMap[pCall->strUUID]=pCall;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnCallNetworkOutgoing: call %s created.\n",pCall->strUUID.c_str());
+ }
+
+ //outgoing uuid and channel name is not yet known.
+ pDevice->AddConnection("", "", pCall, direction_outgoing);
+
+ if(pDevice->IsMonitored())
+ {
+ //TODO: Network Reached
+ }
+ switch_mutex_unlock(m_mutex);
+}
+
+
+
+void FreeSWITCH::OnSessionFinished(CISession* sender)
+{
+ switch_mutex_lock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::OnSessionFinished: removing session 0x%08X\n",sender);
+
+ try
+ {
+ for(MapStr2Device::iterator it=m_DeviceMap.begin();it!=m_DeviceMap.end();it++)
+ {
+ it->second->RemoveMonitor(sender);
+ }
+ }
+ catch(...)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::OnSessionFinished: Exception.");
+ }
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::MonitorStart(CISession* sender, MonitorStartRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::MonitorStart: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ if(!pRequest->GetMonitorObject().GetCallNr().size())
+ {
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation, invalidMonitorObject);
+ sender->SendMsg(&err);
+ return;
+ }
+
+
+ FreeSwitchDeviceType type=FreeSwitchDevice::Device2Type(pRequest->GetMonitorObject());
+ if(type==type_unknown)
+ {
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation, invalidMonitorObject);
+ sender->SendMsg(&err);
+ return;
+ }
+
+ switch_mutex_lock(m_mutex);
+ FreeSwitchDevice* pDevice=PrepareDevice(pRequest->GetMonitorObject().GetCallNr().c_str()+(type==type_internal_subscriber?0:2), type);
+
+ string crossRefID=pDevice->GetDeviceID().c_str();
+ for(crossRefID=pDevice->GetDeviceID();IsXRefIDUsed(crossRefID);crossRefID=GetNextXRefID());
+
+ if(pDevice->AddMonitor(sender, crossRefID))
+ {
+ MonitorStartResponse resp(pRequest->GetInvokeID(),crossRefID);
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::MonitorStart: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ }
+ else
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::MonitorStart: AddMonitor failed.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation, invalidMonitorObject);
+ sender->SendMsg(&err);
+ }
+ switch_mutex_unlock(m_mutex);
+}
+
+
+void FreeSWITCH::SnapshotDevice(CISession* sender, SnapshotDeviceRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SnapshotDevice: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ FreeSwitchDeviceType type=FreeSwitchDevice::Device2Type(pRequest->GetSnapshotObject());
+ if(type==type_unknown)
+ {
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation, invalidDeviceID);
+ sender->SendMsg(&err);
+ return;
+ }
+
+ switch_mutex_lock(m_mutex);
+ FreeSwitchDevice* pDevice=PrepareDevice(pRequest->GetSnapshotObject().GetCallNr().c_str()+(type==type_internal_subscriber?0:2), type);
+
+ SnapshotDeviceResponse resp(pRequest->GetInvokeID());
+
+ for(MapCall2Connection::iterator it=pDevice->connections.begin();it!=pDevice->connections.end();it++)
+ {
+ SnapshotDeviceData data(ConnectionID(pRequest->GetSnapshotObject(),it->second->pCall->strUUID),it->second->state);
+ resp.AddSnapshotData(data);
+ }
+
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SnapshotDevice: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::SnapshotCall(CISession* sender, SnapshotCallRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SnapshotCall: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+ FreeSwitchCall* pCall=GetCall(pRequest->GetSnapshotObject().GetCallID().c_str());
+ if(!pCall)
+
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::SnapshotCall: CallID %s not found.",pRequest->GetSnapshotObject().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SnapshotCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ SnapshotCallResponse resp(pRequest->GetInvokeID());
+
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ {
+ FreeSwitchConnection* pConn=it->second->FindConnection(pCall);
+ SnapshotCallData data(it->second->GetDeviceID(),pConn?pConn->state:STATE_NULL);
+ resp.AddSnapshotData(data);
+ }
+ string caller, called;
+ FindCallerCalled(pCall->strUUID.c_str(), &caller, &called);
+ resp.SetCallingDevice(caller);
+ resp.SetCalledDevice(called);
+
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SnapshotDevice: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+
+ switch_mutex_unlock(m_mutex);
+
+}
+
+
+void FreeSWITCH::MakeCall(CISession* sender, MakeCallRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::MakeCall: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_channel_t *caller_channel;
+ switch_core_session_t *caller_session = NULL;
+ char aleg[400], exten[400];
+ uint32_t timeout = 60;
+ switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
+ FreeSwitchDevice* pDevice=NULL;
+
+ if(pRequest->GetCallingDevice().GetTypeOfNumber()==typeOfNumberDialable)
+ {
+ sprintf(aleg,"%ssofia/internal/%s%s%s",pRequest->GetAutoOriginate()==ORIGINATE_DO_NOT_PROMPT?"{sip_auto_answer=true}":"",pRequest->GetCallingDevice().GetCallNr().c_str(),"%",switch_core_get_variable("domain"));
+ pDevice=PrepareDevice(pRequest->GetCallingDevice().GetCallNr().c_str());
+ pDevice->SetMakeCallOriginator(true);
+ }
+ else
+ {
+ sprintf(aleg,"loopback/%s",pRequest->GetCallingDevice().GetCallNr().c_str()+2);
+ }
+ sprintf(exten,"%s",pRequest->GetCalledDirectoryNumber().GetCallNr().c_str());
+
+ if (switch_ivr_originate(NULL, &caller_session, &cause, aleg, timeout, NULL, "CSTA", pRequest->GetCallingDevice().GetCallNr().c_str(), NULL, NULL, SOF_NONE) != SWITCH_STATUS_SUCCESS || !caller_session)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "-ERR Cannot Create Outgoing Channel! [%s] cause: %s\n", aleg, switch_channel_cause2str(cause));
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError); //TODO: refine error code
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::MakeCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ if(pDevice)
+ pDevice->SetMakeCallOriginator(false);
+ return;
+ }
+
+ caller_channel = switch_core_session_get_channel(caller_session);
+ switch_channel_clear_state_handler(caller_channel, NULL);
+
+ switch_ivr_session_transfer(caller_session, exten, "XML", "default");
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "+OK Created Session: %s\n", switch_core_session_get_uuid(caller_session));
+
+ MakeCallResponse resp(pRequest->GetInvokeID(),ConnectionID(pRequest->GetCallingDevice(),switch_core_session_get_uuid(caller_session)));
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::MakeCall: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ if(pDevice)
+ pDevice->SetMakeCallOriginator(false);
+
+ switch_core_session_rwunlock(caller_session);
+
+}
+
+
+void FreeSWITCH::AnswerCall(CISession* sender, AnswerCallRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::AnswerCall: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchCall* pCall=GetCall(pRequest->GetCallToBeAnswered().GetCallID().c_str());
+ if(!pCall)
+
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::AnswerCall: CallID %s not found.",pRequest->GetCallToBeAnswered().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::AnswerCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ FreeSwitchDevice * pDevice=pCall->GetDevice(pRequest->GetCallToBeAnswered().GetDeviceID()->GetCallNr());
+ if(!pDevice)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::AnswerCall: Device %s not found.",pRequest->GetCallToBeAnswered().GetDeviceID()->GetCallNr().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::AnswerCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+ FreeSwitchConnection* pConnection=pDevice->FindConnection(pCall);
+ if(!pConnection)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::AnswerCall: Connection %s/%s not found.",pRequest->GetCallToBeAnswered().GetDeviceID()->GetCallNr().c_str(),pRequest->GetCallToBeAnswered().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::AnswerCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+ switch_core_session_t* session=switch_core_session_locate(pConnection->strUUID.c_str());
+
+ if(!session)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::AnswerCall: No session for CallID %s found.",pRequest->GetCallToBeAnswered().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::AnswerCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+ switch_channel_t * channel=switch_core_session_get_channel(session);
+ switch_channel_clear_flag(channel, CF_PROXY_MEDIA);
+ switch_channel_clear_flag(channel, CF_PROXY_MODE);
+ if(switch_channel_answer(channel)==SWITCH_STATUS_SUCCESS)
+ {
+ AnswerCallResponse resp(pRequest->GetInvokeID());
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::AnswerCall: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ }
+ else
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::AnswerCall: switch_channel_answer failed.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::AnswerCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+
+ }
+ switch_core_session_rwunlock(session);
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::PlayMessage(CISession* sender, PlayMessageRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PlayMessage: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchCall* pCall=GetCall(pRequest->GetOverConnection().GetCallID().c_str());
+ if(!pCall)
+
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PlayMessage: CallID %s not found.",pRequest->GetOverConnection().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PlayMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ FreeSwitchDevice * pDevice=pCall->GetDevice(pRequest->GetOverConnection().GetDeviceID()->GetCallNr());
+ if(!pDevice)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PlayMessage: Device %s not found.",pRequest->GetOverConnection().GetDeviceID()->GetCallNr().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PlayMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+ FreeSwitchConnection* pConnection=pDevice->FindConnection(pCall);
+ if(!pConnection)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PlayMessage: Connection %s/%s not found.",pRequest->GetOverConnection().GetDeviceID()->GetCallNr().c_str(),pRequest->GetOverConnection().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PlayMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ if(switch_ivr_broadcast(pConnection->strUUID.c_str(), pRequest->GetMessageToBePlayed().c_str(), SMF_ECHO_ALEG)==SWITCH_STATUS_SUCCESS)
+ {
+ PlayMessageResponse resp(pRequest->GetInvokeID());
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PlayMessage: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ }
+ else
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::PlayMessage: switch_ivr_broadcast failed.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::PlayMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ }
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::RecordMessage(CISession* sender, RecordMessageRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchCall* pCall=GetCall(pRequest->GetCallToBeRecorded().GetCallID().c_str());
+ if(!pCall)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::RecordMessage: CallID %s not found.",pRequest->GetCallToBeRecorded().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ FreeSwitchDevice * pDevice=pCall->GetDevice(pRequest->GetCallToBeRecorded().GetDeviceID()->GetCallNr());
+ if(!pDevice)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::RecordMessage: Device %s not found.",pRequest->GetCallToBeRecorded().GetDeviceID()->GetCallNr().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+ FreeSwitchConnection* pConnection=pDevice->FindConnection(pCall);
+ if(!pConnection)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::RecordMessage: Connection %s/%s not found.",pRequest->GetCallToBeRecorded().GetDeviceID()->GetCallNr().c_str(),pRequest->GetCallToBeRecorded().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ switch_core_session_t *session=switch_core_session_locate(pConnection->strUUID.c_str());
+ if(!session)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::RecordMessage: Session %s not found.",pConnection->strUUID.c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+
+ if ((switch_channel_test_flag(switch_core_session_get_channel(session), CF_EVENT_PARSE)))
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::RecordMessage: Record or broadcast already in progress.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ char filename[MAX_PATH];
+ sprintf(filename,"%s-%X.wav",pRequest->GetCallToBeRecorded().GetCallID().c_str(),clock());
+ char arg[MAX_PATH+20];
+
+ if(pRequest->GetMaxDuration()>1000)
+ {
+ sprintf(arg, "%s %d",filename,pRequest->GetMaxDuration()/1000);
+ }
+ else
+ {
+ strcpy(arg,filename);
+ }
+
+ char path[MAX_PATH];
+ strcat(path,switch_channel_get_variable(switch_core_session_get_channel(session), "sound_prefix"));
+ strcat(path,SWITCH_PATH_SEPARATOR);
+ strcat(path,filename);
+
+ switch_event_t *event;
+ if (switch_event_create(&event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS)
+ {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-name", "record");
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "execute-app-arg", arg);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event-lock", "true");
+ switch_core_session_queue_private_event(session, &event);
+
+ RecordMessageResponse resp(pRequest->GetInvokeID(),path);
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ }
+ else
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::RecordMessage: switch_event_create failed.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ }
+ switch_core_session_rwunlock(session);
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::StopMessage(CISession* sender, StopRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::StopMessage: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchCall* pCall=GetCall(pRequest->GetConnection().GetCallID().c_str());
+ if(!pCall)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::StopMessage: CallID %s not found.",pRequest->GetConnection().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::StopMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ FreeSwitchDevice * pDevice=pCall->GetDevice(pRequest->GetConnection().GetDeviceID()->GetCallNr());
+ if(!pDevice)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::StopMessage: Device %s not found.",pRequest->GetConnection().GetDeviceID()->GetCallNr().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::StopMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+ FreeSwitchConnection* pConnection=pDevice->FindConnection(pCall);
+ if(!pConnection)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::StopMessage: Connection %s/%s not found.",pRequest->GetConnection().GetDeviceID()->GetCallNr().c_str(),pRequest->GetConnection().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::StopMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ switch_core_session_t *session=switch_core_session_locate(pConnection->strUUID.c_str());
+ if(!session)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::StopMessage: Session %s not found.",pConnection->strUUID.c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::StopMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ if (!switch_channel_test_flag(switch_core_session_get_channel(session), CF_EVENT_PARSE))
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::RecordMessage:No record or broadcast running.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::RecordMessage: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ switch_ivr_stop_record_session(session, pRequest->GetMessageToBeStopped().size()?pRequest->GetMessageToBeStopped().c_str():"all");
+ switch_channel_stop_broadcast(switch_core_session_get_channel(session));
+
+ StopResponse resp(pRequest->GetInvokeID());
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::StopMessage: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+
+ switch_core_session_rwunlock(session);
+ switch_mutex_unlock(m_mutex);
+}
+
+
+void FreeSWITCH::SingleStepTransferCall(CISession* sender,SingleStepTransferCallRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SingleStepTransferCall: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchCall* pCall=GetCall(pRequest->GetActiveCall().GetCallID().c_str());
+ if(!pCall)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::SingleStepTransferCall: CallID %s not found.",pRequest->GetActiveCall().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SingleStepTransferCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ //Retrieving the device that initiates the transfer
+ FreeSwitchDevice * pTransferringDevice=pCall->GetDevice(pRequest->GetActiveCall().GetDeviceID()->GetCallNr());
+ if(!pTransferringDevice)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::SingleStepTransferCall: Device %s not found.",pRequest->GetActiveCall().GetDeviceID()->GetCallNr().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SingleStepTransferCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ {
+ if(it->second!=pTransferringDevice)
+ {
+ FreeSwitchConnection* pConnectionToTransfer=it->second->FindConnection(pCall);
+ if(!pConnectionToTransfer)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::SingleStepTransferCall: Connection %s/%s not found.",it->second->GetDeviceID().c_str(),pRequest->GetActiveCall().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SingleStepTransferCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ switch_core_session_t* sessionToTransfer=switch_core_session_locate(pConnectionToTransfer->strUUID.c_str());
+ if(!sessionToTransfer)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::SingleStepTransferCall: Session %s not found.",pConnectionToTransfer->strUUID.c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SingleStepTransferCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ if(switch_ivr_session_transfer(sessionToTransfer,pRequest->GetTransferredTo().GetCallNr().c_str(),NULL,NULL)==SWITCH_STATUS_SUCCESS)
+ {
+ SingleStepTransferCallResponse resp(pRequest->GetInvokeID(),ConnectionID(pRequest->GetTransferredTo(),pCall->strUUID));
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SingleStepTransferCall: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ }
+ else
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::SingleStepTransferCall: switch_ivr_session_transfer failed.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::SingleStepTransferCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ }
+ switch_core_session_rwunlock(sessionToTransfer);
+ }
+ }
+
+ //TODO: send transferred event
+ pTransferringDevice->DeleteConnection(pCall);
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::DeflectCall(CISession* sender,DeflectCallRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::DeflectCall: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchCall* pCall=GetCall(pRequest->GetCallToBeDiverted().GetCallID().c_str());
+ if(!pCall)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::DeflectCall: CallID %s not found.",pRequest->GetCallToBeDiverted().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::DeflectCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ //Retrieving the device that initiates the transfer
+ FreeSwitchDevice * pTransferringDevice=pCall->GetDevice(pRequest->GetCallToBeDiverted().GetDeviceID()->GetCallNr());
+ if(!pTransferringDevice)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::DeflectCall: Device %s not found.",pRequest->GetCallToBeDiverted().GetDeviceID()->GetCallNr().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::DeflectCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ for(MapStr2Device::iterator it=pCall->devices.begin();it!=pCall->devices.end();it++)
+ {
+ if(it->second!=pTransferringDevice)
+ {
+ FreeSwitchConnection* pConnectionToTransfer=it->second->FindConnection(pCall);
+ if(!pConnectionToTransfer)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::DeflectCall: Connection %s/%s not found.",it->second->GetDeviceID().c_str(),pRequest->GetCallToBeDiverted().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::DeflectCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ switch_core_session_t* sessionToTransfer=switch_core_session_locate(pConnectionToTransfer->strUUID.c_str());
+ if(!sessionToTransfer)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::DeflectCall: Session %s not found.",pConnectionToTransfer->strUUID.c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::DeflectCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ if(switch_ivr_session_transfer(sessionToTransfer,pRequest->GetNewDestination().GetCallNr().c_str(),NULL,NULL)==SWITCH_STATUS_SUCCESS)
+ {
+ DeflectCallResponse resp(pRequest->GetInvokeID());
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::DeflectCall: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ }
+ else
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::DeflectCall: switch_ivr_session_transfer failed.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::DeflectCall: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ }
+ switch_core_session_rwunlock(sessionToTransfer);
+ }
+ }
+
+ //TODO: send transferred event
+ pTransferringDevice->DeleteConnection(pCall);
+
+ switch_mutex_unlock(m_mutex);
+}
+
+void FreeSWITCH::ClearConnection(CISession* sender, ClearConnectionRequest* pRequest)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::ClearConnection: Request with InvokeID: %d\n:%s\n",pRequest->GetInvokeID(), pRequest->GetReadable().c_str());
+
+ switch_mutex_lock(m_mutex);
+
+ FreeSwitchCall* pCall=GetCall(pRequest->GetConnectionToBeCleared().GetCallID().c_str());
+ if(!pCall)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::ClearConnection: CallID %s not found.",pRequest->GetConnectionToBeCleared().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidCallID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::ClearConnection: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ //Retrieving the device that initiates the transfer
+ FreeSwitchDevice * pDevice=pCall->GetDevice(pRequest->GetConnectionToBeCleared().GetDeviceID()->GetCallNr());
+ if(!pDevice)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::ClearConnection: Device %s not found.",pRequest->GetConnectionToBeCleared().GetDeviceID()->GetCallNr().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::ClearConnection: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ FreeSwitchConnection* pConnection=pDevice->FindConnection(pCall);
+ if(!pConnection)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::ClearConnection: Connection %s/%s not found.",pDevice->GetDeviceID().c_str(),pRequest->GetConnectionToBeCleared().GetCallID().c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::ClearConnection: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ switch_core_session_t* session=switch_core_session_locate(pConnection->strUUID.c_str());
+ if(!session)
+ {
+ switch_mutex_unlock(m_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::ClearConnection: Session %s not found.",pConnection->strUUID.c_str());
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,invalidDeviceID);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::ClearConnection: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ return;
+ }
+
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ if(switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING)==CS_HANGUP)
+ {
+ ClearConnectionResponse resp(pRequest->GetInvokeID());
+ sender->SendMsg(&resp);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::ClearConnection: Response sent with InvokeID: %d\n:%s\n",resp.GetInvokeID(), resp.GetReadable().c_str());
+ }
+ else
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "FreeSWITCH::ClearConnection: switch_ivr_session_transfer failed.");
+ UniversalErrorResponse err(pRequest->GetInvokeID(),error_type_operation,genericError);
+ sender->SendMsg(&err);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "FreeSWITCH::ClearConnection: Response sent with InvokeID: %d\n:%s\n",err.GetInvokeID(), err.GetReadable().c_str());
+ }
+ switch_core_session_rwunlock(session);
+ switch_mutex_unlock(m_mutex);
+}
\ No newline at end of file
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCH.h (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCH.h 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,248 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+#ifndef CI_FREE_SWITCH_H
+#define CI_FREE_SWITCH_H
+
+#include "CICTIHandler.h"
+#include "CISession.h"
+#include "CSTAEvent.h"
+#include <map>
+#include <list>
+#include <string>
+
+
+using namespace std;
+
+
+
+class FreeSwitchCall;
+
+enum eDirection
+{
+ direction_incoming, //!< attached device is the called (on internal subscriber) or call is incoming (on network interface)
+ direction_outgoing, //!< attached device is the caller (on internal subscriber) or call is outgoing (on network interface)
+};
+
+class FreeSwitchConnection
+{
+public:
+ FreeSwitchCall* pCall;
+ string strUUID; //<! Unique ID of the connection (could be different from the call's unique ID)
+ eLocalConnectionState state; //!< Local connection state
+ eDirection direction; //!< direction of the call
+ string strChannel; //!< channel name
+};
+
+typedef map<FreeSwitchCall*,FreeSwitchConnection*> MapCall2Connection;
+typedef map<string, CISession*> MapStr2Session;
+
+enum FreeSwitchDeviceType
+{
+ type_internal_subscriber=0,
+ type_network_interface,
+ type_queue,
+ type_unknown,
+};
+
+class FreeSwitchDevice
+{
+protected:
+ string m_strDevice;
+ MapStr2Session m_MonitoringSessions; //!< Sessions monitoring this device
+
+ FreeSwitchDeviceType m_deviceType;
+
+ bool m_bIsMakeCallOriginator;
+public:
+ static std::string Channel2Device(const char* channel);
+
+ static char * Type2Prefix(FreeSwitchDeviceType type);
+
+ //! finds out FreeSWITCH device type of CSTA DeviceID object
+ /*!
+ CSTA devices with type "dialingNumber" will mapped to internal subscribers (Note, that in some cases,
+ the implementation will ignore the type field in CSTA devices and interprets the CallNr as a dial string,
+ e.g in MakeCall request the device type is checked for callingDevice but not for calledDirectoryNumber).
+
+ CSTA devices with type "deviceNumber" are used to represent non subscriber type entities.
+ For FreeSWITCH implementation, the number string begins with 2 byte long device
+ type identifier and a device identifier. The device identifier must only contain numeric characters
+
+ Current device type prefixes:
+ "02" - Queue
+
+ \sa queue_function
+ */
+ static FreeSwitchDeviceType Device2Type(DeviceID device);
+public:
+ MapCall2Connection connections; //!< Active connections of this device
+
+ FreeSwitchDevice(const char* pcDevice, FreeSwitchDeviceType deviceType=type_internal_subscriber);
+
+ string& GetDeviceID() {return m_strDevice;}
+
+ bool IsMonitoredWithID(string crossRefID);
+
+ bool AddMonitor(CISession* session, string crossRefID);
+
+ bool RemoveMonitor(CISession* session);
+
+ bool RemoveMonitor(CISession* session, string crossRefID);
+
+ bool IsMonitored() {return m_MonitoringSessions.size()>0?true:false;}
+
+ FreeSwitchConnection* FindConnection(const char* uuid);
+
+ FreeSwitchConnection* FindConnection(FreeSwitchCall* pCall);
+
+ FreeSwitchConnection* AddConnection(const char* uuid, const char * channel, FreeSwitchCall* pCall, eDirection direction);
+
+ void DeleteConnection(FreeSwitchCall* pCall);
+
+ //! Sends CSTA event to all sessions monitoring the device
+ void SendEvent(CSTAEvent* pEvent);
+
+ FreeSwitchDeviceType GetDeviceType() {return m_deviceType;}
+
+ int GetConnectionCount() {return connections.size();}
+
+ bool IsMakeCallOriginator() {return m_bIsMakeCallOriginator;}
+
+ void SetMakeCallOriginator (bool bMakeCallOriginator) {m_bIsMakeCallOriginator=bMakeCallOriginator;}
+};
+
+typedef map<string,FreeSwitchDevice*> MapStr2Device;
+typedef map<string,FreeSwitchCall*> MapStr2Call;
+
+class FreeSwitchCall
+{
+public:
+ string strUUID; //!< Unique ID (used for CSTA CallID) - the FreeSWITCH unique ID of the first connection in the call.
+ MapStr2Device devices;
+
+ FreeSwitchDevice* GetDevice(std::string strDeviceID);
+};
+
+
+
+
+//! CSTA Inside CICTIHandler interface realization for FreeSWITCH.
+/*!
+Provides FreeSWITCH specific telephony methods to used by CSTA Inside.
+*/
+class FreeSWITCH : public CICTIHandler
+{
+protected:
+ MapStr2Device m_DeviceMap; //!< Stores the known devices. Map key is the device id (usually the dialing number)
+ MapStr2Call m_CallMap; //!< Stores the active calls. Map key is the call ID (1st FreeSWITCH UUID)
+ switch_mutex_t *m_mutex; //!< To protect the device and call map
+ switch_memory_pool_t * m_pool;
+
+ int m_nLastXRefID;
+
+ bool FindCallerCalled(const char* uuid, string* pstrCaller, string* pstrCalled);
+
+ bool PrepareCallData(const char* uuid, const char* uuid2, const char* channel, FreeSwitchDevice** ppDevice, FreeSwitchCall** ppCall, FreeSwitchConnection** ppConnection, bool bCreateCall, FreeSwitchDevice** ppQueue, FreeSwitchDevice** ppInboundNID, FreeSwitchDevice** ppOutboundNID, string* pstrCaller, string* pstrCalled);
+
+public:
+ FreeSWITCH(switch_memory_pool_t *pool);
+
+ virtual ~FreeSWITCH();
+
+ FreeSwitchDevice * PrepareDevice(const char * pcDevice, FreeSwitchDeviceType type=type_internal_subscriber);
+
+ FreeSwitchCall* GetCall(const char * pcUUID);
+
+ bool IsXRefIDUsed(string crossRefID); //!< Returns true if given XRefID already used in the current CTI handler
+
+ string GetNextXRefID(); //!< Returns the next available monitor cross reference ID
+
+//Switch event handlers:
+ void OnChannelCreate(switch_event_t *event); //!< Handling CHANNEL_CREATE FreeSwitch event
+
+ void OnChannelHangup(switch_event_t *event); //!< Handling CHANNEL_HANGUP FreeSwitch event
+
+ void OnChannelAnswer(switch_event_t *event); //!< Handling CHANNEL_ANSWER FreeSwitch event
+
+ void OnProgress(switch_event_t *event); //!< Handling CHANNEL_PROGRESS_MEDIA and CHANNEL_PROGRESS events
+
+ void OnDtmf(switch_event_t *event); //!< Handling DTMF FreeSWITCH event
+
+ void OnCallQueued(const char* queue, switch_core_session_t *session); //!< Handling incoming call on queue
+
+ void OnCallNetworkIncoming(const char* trunk, switch_core_session_t *session); //!< Handling incoming call on a gateway
+
+ void OnCallNetworkOutgoing(const char* trunk, switch_core_session_t *session); //!< Handling outgoing call on a gateway
+
+ void OnPlayback(switch_event_t *event); //!< Handling playback application start or stop
+
+ void OnRecord(switch_event_t *event); //!< Handling record application start or stop
+
+//Session event handlers:
+
+ void OnSessionFinished(CISession* sender); //!< Called if given session is disconnected
+
+ void MonitorStart(CISession* sender, MonitorStartRequest* pRequest); //!< called if a Monitor Start request should be processed
+
+ void SnapshotDevice(CISession* sender, SnapshotDeviceRequest* pRequest); //!< Called if Snapshot Device request is received
+
+ void SnapshotCall(CISession* sender, SnapshotCallRequest* pRequest); //!< Called if Snapshot Call request is received
+
+
+ void MakeCall(CISession* sender, MakeCallRequest* pRequest); //!< Called if Make Call request is received
+
+ void AnswerCall(CISession* sender, AnswerCallRequest* pRequest); //!< Called if Answer Call request is received
+
+ void PlayMessage(CISession* sender, PlayMessageRequest* pRequest); //!< Called if Play Message request is received
+
+ void RecordMessage(CISession* sender, RecordMessageRequest* pRequest); //!< Called if Record Message request is received
+
+ void StopMessage(CISession* sender, StopRequest* pRequest); //!< Called if Stop request is received
+
+ void SingleStepTransferCall(CISession* sender,SingleStepTransferCallRequest* pRequest); //!< Called if Single Step Transfer Call Message request is received
+
+ void ClearConnection(CISession* sender,ClearConnectionRequest* pRequest);
+
+ void DeflectCall(CISession* sender,DeflectCallRequest* pRequest); //!< Called if Deflect Call Message request is received
+};
+
+#endif //CI_FREE_SWITCH_H
\ No newline at end of file
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHPlatform.cpp (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHPlatform.cpp 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,72 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+#include "FreeSWITCHPlatform.h"
+#include "switch.h"
+
+
+FreeSWITCHPlatform::FreeSWITCHPlatform(void)
+{
+}
+
+FreeSWITCHPlatform::~FreeSWITCHPlatform(void)
+{
+}
+
+void FreeSWITCHPlatform::Trace(ci_trace_level loglevel, const char *fmt, ...)
+{
+ switch_log_level_t fsloglevel=SWITCH_LOG_ALERT;
+ switch (loglevel)
+ {
+ case CI_LLV_FATAL: fsloglevel=SWITCH_LOG_ALERT;break;
+ case CI_LLV_ERROR: fsloglevel=SWITCH_LOG_ERROR;break;
+ case CI_LLV_WARN: fsloglevel=SWITCH_LOG_WARNING;break;
+ case CI_LLV_INFO: fsloglevel=SWITCH_LOG_NOTICE;break;
+ case CI_LLV_DEBUG: fsloglevel=SWITCH_LOG_DEBUG;break;
+ }
+
+ va_list ap;
+ va_start(ap, fmt);
+
+
+ switch_log_vprintf(SWITCH_CHANNEL_LOG, fsloglevel, fmt, ap);
+ va_end(ap);
+}
\ No newline at end of file
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHPlatform.h (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHPlatform.h 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,62 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+
+#ifndef CI_FREE_SWITCH_PLATFORM_H
+#define CI_FREE_SWITCH_PLATFORM_H
+
+#include "CIPlatform.h"
+
+//! CSTA Inside CIPlatform interface realization for FreeSWITCH.
+/*!
+Provides FreeSWITCH platform specific OS/XML/... methods required by by CSTA Inside.
+*/
+class FreeSWITCHPlatform : public CIPlatform
+{
+public:
+ FreeSWITCHPlatform();
+
+ virtual ~FreeSWITCHPlatform();
+
+ virtual void Trace(ci_trace_level loglevel, const char *fmt, ...);
+};
+
+#endif //CI_FREE_SWITCH_PLATFORM_H
\ No newline at end of file
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHSocket.cpp (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHSocket.cpp 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,98 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+
+#include "FreeSwitchSocket.h"
+#include <apr_errno.h>
+
+FreeSWITCHSocket::FreeSWITCHSocket(switch_socket_t* pSocket, switch_memory_pool_t *pool) : m_pSocket(pSocket), m_pool(pool)
+{
+ switch_mutex_init(&m_mutex, SWITCH_MUTEX_NESTED, m_pool);
+ switch_socket_opt_set(m_pSocket, SWITCH_SO_TCP_NODELAY, TRUE);
+ switch_socket_opt_set(m_pSocket, SWITCH_SO_NONBLOCK, FALSE);
+
+ char remote_ip[50];
+ switch_sockaddr_t *sa;
+
+ switch_socket_addr_get(&sa, SWITCH_TRUE, m_pSocket);
+ switch_get_addr(remote_ip, sizeof(remote_ip), sa);
+ switch_port_t remote_port = switch_sockaddr_get_port(sa);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Connection Open from %s:%d\n", remote_ip, remote_port);
+}
+
+FreeSWITCHSocket::~FreeSWITCHSocket()
+{
+ switch_mutex_destroy(m_mutex);
+}
+
+int FreeSWITCHSocket::Receive(unsigned char *buf, size_t *len)
+{
+ switch_status_t status=switch_socket_recv(m_pSocket, (char*)buf, len);
+ if(status)
+ {
+ char errbuf[4096];
+ switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_NOTICE,"Receive: socket terminated: %d (%s)",status, apr_strerror(status,errbuf,sizeof(errbuf)));
+ }
+ else
+ switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_NOTICE,"%d bytes received:\n%s",*len, buf);
+ return status;
+}
+
+int FreeSWITCHSocket::Send(const unsigned char *buf, size_t *len)
+{
+ switch_mutex_lock(m_mutex);
+ switch_status_t status=switch_socket_send(m_pSocket, (const char*)buf, len);
+ if(status)
+ {
+ char errbuf[4096];
+ switch_log_printf(SWITCH_CHANNEL_LOG,SWITCH_LOG_NOTICE,"Send: socket terminated: %d (%s)",status, apr_strerror(status,errbuf,sizeof(errbuf)));
+ }
+ switch_mutex_unlock(m_mutex);
+ return status;
+}
+
+int FreeSWITCHSocket::Close()
+{
+ switch_socket_shutdown(m_pSocket, SWITCH_SHUTDOWN_READWRITE);
+ switch_socket_close(m_pSocket);
+ return 0;
+}
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHSocket.h (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCHSocket.h 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,71 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+
+#ifndef CI_FREE_SWITCH_SOCKET_H
+#define CI_FREE_SWITCH_SOCKET_H
+
+#include "CISocket.h"
+#include "switch.h"
+
+//! CSTA Inside CISocket interface realization for FreeSWITCH.
+/*!
+Provides FreeSWITCH platform specific socket manipulation methods required by CSTA Inside.
+*/
+class FreeSWITCHSocket : public CISocket
+{
+protected:
+ switch_socket_t* m_pSocket;
+ switch_mutex_t *m_mutex;
+ switch_memory_pool_t* m_pool;
+public:
+ FreeSWITCHSocket(switch_socket_t* pSocket, switch_memory_pool_t *pool);
+
+ virtual ~FreeSWITCHSocket();
+
+ virtual int Receive(unsigned char *buf, size_t *len);
+
+ virtual int Send(const unsigned char *buf, size_t *len);
+
+ virtual int Close();
+};
+
+#endif //CI_FREE_SWITCH_SOCKET_H
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCH_CSTA.rc (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/FreeSWITCH_CSTA.rc 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,115 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// Hungarian resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_HUN)
+#ifdef _WIN32
+LANGUAGE LANG_HUNGARIAN, SUBLANG_DEFAULT
+#pragma code_page(1250)
+#endif //_WIN32
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // Hungarian resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 0,2,0,92
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x17L
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x4L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040e04b0"
+ BEGIN
+ VALUE "Comments", "http://cstainside.sourceforge.net/"
+ VALUE "FileDescription", "CSTA interface for FreeSWITCH"
+ VALUE "FileVersion", "0, 2, 0, 92"
+ VALUE "InternalName", "mod_csta_socket"
+ VALUE "LegalCopyright", "Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>"
+ VALUE "LegalTrademarks", "Licensed under MPL 1.1"
+ VALUE "OriginalFilename", "mod_csta_socket.dll"
+ VALUE "ProductName", "CSTA Inside"
+ VALUE "ProductVersion", "1, 0, 0, 1"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x40e, 1200
+ END
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/README (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/README 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,192 @@
+ mod_csta_socket - CSTA interface for FreeSWITCH
+
+
+1. Capabilities
+
+As a communication & encoding interface CSTA XML over TCP without SOAP is supported yet (ECMA-323 Annex J-2).
+Module is based on CSTA Inside library.
+
+Supported device types:
+
+1.1. internal subscribers
+- internal subscribers are mapped to CSTA "dialingNumber" type of devices. The dialing sequence is the
+phone number without any leading characters
+
+1.2 queues
+Queues are able to enqueue multiple calls. To configure a CSTA queue, add the csta_trigger_queue application
+to a dialplan entry:
+
+<action application="csta_trigger_queue" data="9500"/>
+
+Data is the name of the queue. In CSTA events and requeust, the queue will be referenced as a device with type
+of "deviceNumber". The callNr will be concatenated with a type ID of "02" and the queue name (029500 on the above example).
+Queue name should be numeric to comply with CSTA standard.
+
+1.3 network interfaces
+Network interfaces or trunks representing devices via calls can leave or enter the CSTA subdomain.
+To configure CSTA NIDs, add the csta_trigger_trunk_inbound and csta_trigger_trunk_outbound application
+to the corresponding dialplan entry (if a call is directed to a gateway or external call directed into FreeSWITCH):
+
+outgoing example:
+
+<extension name="outbound_example">
+ <condition field="destination_number" expression="^20(.*)$">
+ <action application="csta_trigger_trunk_outbound" data="20"/>
+ <action application="bridge" data="sofia/gateway/example_gw/$1"/>
+ </condition>
+</extension>
+
+incoming example:
+
+<extension name="inbound_example">
+ <condition field="destination_number" expression="^193190$">
+ <action application="csta_trigger_trunk_inbound" data="20"/>
+ <action application="set" data="domain_name=$${domain}"/>
+ <action application="transfer" data="9500 XML default"/>
+ </condition>
+ </extension>
+
+Data is the name of the queue. In CSTA events and requeust, the NID will be referenced as a device with type
+of "deviceNumber". The callNr will be concatenated with a type ID of "01" and the NID name (0120 on the above example).
+NID name should be numeric to comply with CSTA standard.
+
+The following CSTA messages are implemented:
+
+requests and responses:
+- Monitor Start
+ Starts monitoring of a device.
+ Supported types: internal subscriber, queue, NID
+
+- Make Call
+ Originates a call to an extension
+ Supported types: callingDevice: internal subscriber
+ calledDirectoryNumber: any extension, used as dialing string
+ Do Not Prompt (auto originate) option works only with devices supporting sip_auto_answer flag
+
+- Answer Call
+ Answers a ringing call
+ Supported Types: queue
+
+- Single Step Transfer Call
+ Transfers a connection to another endpoint without hold & consultation
+ Supported types: activeCall: internal subscriber, queue.
+ transferredTo: any extension, used as dialing string.
+
+- Play Message
+ Plays a wavefile for a connected connection. Wavefile path relative to "/sounds/en/us/callie" is to specify in
+ messageToBePlayed parameter. If positive response is returned, check Stop event for result of the service.
+ Supported types: internal subscriber, queue
+
+- Record Message
+ Records a connection to a wavefile. Filename is generated by the service and returned (with full path) in the response.
+ Supported types: internal subscriber, queue
+
+- Stop
+ Stops playing or recording of a wavefile.
+ Supported types: internal subscriber, queue
+
+- Clear Connection
+ Clears an active connection.
+ Supported types: internal subscriber, queue, NID
+
+- Snapshot Device
+ Returns the active connections of a device.
+ Supported types: internal subscriber, queue, NID
+
+- Snapshot Call
+ Returns the devices participating in an active call.
+ Supported types: internal subscriber, queue, NID
+
+- Deflect Call
+ Transfers a connection to another endpoint
+ Supported types: callToBeDiverted: internal subscriber, queue.
+ newDestination: any extension, used as dialing string.
+
+events:
+- Service Initiated
+ Generated if an outbound channel is created from a device
+ Supported types: internal subscriber, network interface
+
+- Originated
+ Generated from the caller if call is delivered
+ Supported types: internal subscriber
+
+- Delivered
+ Generated if call is delivered to called party
+ Supported types: internal subscriber
+
+- Established
+ Generated if channel is answered
+ Supported types: internal subscriber, queue, network interface
+
+- Connection Cleared
+ Generated if a device leaves a call
+ Supported types: internal subscriber, queue, network interface
+
+- Queued
+ Generated if a call enters a queue
+ Supported types: internal subscriber, queue, network interface
+
+- DTMF Detected
+ Generated if a DTMF tone is detected on a connected connection
+ Supported types: internal subscriber, queue (if a device connected to a queue generates a tone), network interface
+ Note: On queues FreeSWITCH only detects DTMF if acoustic conection is on.
+ Workaround: add <action application="playback" data="silence_stream://1800000"/> after queue is answered to queue dialplan.
+
+- Play
+ Generated if playback application is started.
+ The "message" field contains the soundfile relative path.
+
+- Record
+ Generated if record application is started.
+ The "message" field contains the soundfile relative path.
+
+- Stop
+ Generated if playback or record application is stopped.
+ The "message" field contains the soundfile relative path. The "cause" field is set to "endOfMessageDetected" if
+ file played successfully or stop service is invoked, "resourcesNotAvailable" if file not found, and "blocked" if playback failed from any other reason.
+ For recording "messageDurationExceeded" cause is used if record stopped after recording length reached maxDuration or stop service is invoked.
+ If recording stopped because of hangup, no Stop event will be generated, only Connection Cleared.
+
+
+2. Building from source
+
+For Win32 platform Visual Studio 2008 project file is included. Use only Release configuration.
+
+Requirements:
+- CSTA Inside Core - Multi-purpose C++ CSTA-XML library
+ download from: http://cstainside.sourceforge.net/
+ place to: <root>\CSTAInsideCore (project file expects ..\CSTAInsideCore directory)
+- FreeSWITCH
+ download from: http://wiki.freeswitch.org/wiki/Installation_Guide#Download_Source_Tarball
+ place to: <root>\3rdparty\freeswitch-snapshot
+
+Both must be build before building mod_csta_socket
+
+3. Usage
+
+mod_csta_socket.dll is placed to <root>\3rdparty\freeswitch-snapshot\Release\mod directory. To load use load
+FreeSWITCH command or set automatic load in modules.conf.xml
+
+4. Configuration
+
+module reads configuration data from csta_socket.conf.xml file under <freeswitch>\conf\autoload_configs directory.
+
+Example:
+<configuration name="csta_socket.conf" description="CSTA Interface">
+ <settings>
+ <param name="listen-ip" value="127.0.0.1"/>
+ <param name="xml-listen-port" value="3000"/>
+ <param name="apply-inbound-acl" value="csta"/>
+ </settings>
+</configuration>
+
+listen-ip: the IP address of interface to listen on. 0.0.0.0 specifies to listen on all interfaces.
+ default: 127.0.0.1
+xml-listen-port: the listening port for CSTA-XML over TCPinterface.
+ default: 3000
+apply-inbound-acl: the name of ACL entry configured in acl.conf to filter inbound connections.
+ default: empty (no ACL applied)
+
+
+Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
\ No newline at end of file
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/config.cpp (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/config.cpp 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,88 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+#include <switch.h>
+#include "config.h"
+
+
+/*static*/ Config Config::_instance;
+
+Config::Config()
+{
+ strcpy(listen_address,"127.0.0.1");
+ xml_port=3000;
+ acl_name[0]=0;
+}
+
+bool Config::ReadConfig()
+{
+
+ char *cf = "csta_socket.conf";
+ switch_xml_t cfg, xml, settings, param;
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Open of %s failed, using defaults.\n", cf);
+ } else {
+ if ((settings = switch_xml_child(cfg, "settings"))) {
+ 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, "listen-ip"))
+ {
+ strncpy(listen_address,val,sizeof(listen_address));
+ listen_address[sizeof(listen_address)-1]=0;
+ }
+ else if (!strcmp(var, "xml-listen-port"))
+ xml_port=(switch_port_t)atoi(val);
+ else if (!strcasecmp(var, "apply-inbound-acl"))
+ {
+ strncpy(acl_name,val,sizeof(acl_name));
+ acl_name[sizeof(acl_name)-1]=0;
+ }
+ }
+ }
+ switch_xml_free(xml);
+ }
+
+ return true;
+
+}
\ No newline at end of file
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/config.h (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/config.h 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,73 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+#ifndef CI_FS_CONFIG_H
+#define CI_FS_CONFIG_H
+
+
+//! Stores module configuration and processes module configuration file.
+class Config
+{
+protected:
+ static Config _instance;
+public:
+ static Config* Instance() {return &_instance;}
+protected:
+ char listen_address[50];
+ switch_port_t xml_port;
+ char acl_name[50];
+protected:
+ Config();
+public:
+ bool ReadConfig();
+
+ const char* GetListenAddress() {return listen_address;}
+
+ const switch_port_t GetXmlPort() {return xml_port;}
+
+ bool IsACLEnabled() {return acl_name[0]==0?false:true;}
+
+ const char* GetACLName() {return acl_name;}
+};
+
+
+
+#endif //CI_FS_CONFIG_H
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/mod_csta_socket.cpp (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/mod_csta_socket.cpp 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,476 @@
+/*
+ * CSTA interface for FreeSWICH
+ * Copyright (C) 2009, Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ * 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 CSTA interface for FreeSWICH
+ *
+ * The Initial Developer of the Original Code is
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Szentesi Krisztian <sz.krisz@freemail.hu>
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ */
+
+/*! \file mod_csta_socket.cpp
+\brief PBX module interface implementation for FreeSWITCH.
+
+Provides interface functions to allow integrate the module to FreeSWITCH
+*/
+
+
+#include <switch.h>
+
+#include "FreeSwitch.h"
+#include "FreeSwitchPlatform.h"
+#include "FreeSwitchSocket.h"
+#include "XMLSession.h"
+#include "config.h"
+#include "UniversalErrorResponse.h"
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_csta_socket_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_csta_socket_shutdown);
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_csta_socket_runtime);
+SWITCH_MODULE_DEFINITION(mod_csta_socket, mod_csta_socket_load, mod_csta_socket_shutdown, mod_csta_socket_runtime);
+
+static volatile bool bRunning=true;
+
+FreeSWITCH* fs=NULL;
+FreeSWITCHPlatform* platform=NULL;
+
+
+struct THREAD_INFO
+{
+ switch_memory_pool_t *pool;
+ switch_socket_t* socket;
+};
+
+
+switch_socket_t* listen_socket=NULL;
+switch_event_node_t *node=NULL;
+
+
+//! Called if a call hits a queue
+/*!
+ Called if call enters into a queue. Queues should be defined in dialplan
+ default section with csta_trigger_queue application triggered.
+ \param session The FreeSWITCH session
+ \param data The queue name set in dialplan (data parameter of csta_trigger_queue application)
+
+ Example configuration:
+
+ <extension name="example_queue">
+ <condition field="destination_number" expression="^9500$">
+ <action application="ring_ready"/>
+ <action application="csta_trigger_queue" data="9500"/>
+ <action application="sleep" data="600000"/>
+ </condition>
+ </extension>
+
+ Note that queue name must only contain numeric characters to fit CSTA standard
+*/
+SWITCH_STANDARD_APP(queue_function)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Queue triggered, queue: %s, call:%s!\n", data, switch_core_session_get_uuid(session));
+ fs->OnCallQueued(data, session);
+}
+
+
+//! Called if a call enters FreeSWITCH from outside
+/*!
+ Called if a call enters FreeSWITCH from outside. Incoming CSTA Network interfaces should be defined in dialplan
+ public section with csta_trigger_trunk_inbound application triggered.
+ \param session The FreeSWITCH session
+ \param data The NID name set in dialplan (data parameter of csta_trigger_trunk_inbound application)
+
+ Example configuration:
+
+ <extension name="inbound_example">
+ <condition field="destination_number" expression="^193190$">
+ <action application="csta_trigger_trunk_inbound" data="20"/>
+ <action application="set" data="domain_name=$${domain}"/>
+ <action application="transfer" data="9500 XML default"/>
+ </condition>
+ </extension>
+
+ Note that NID name must only contain numeric characters to fit CSTA standard
+*/
+SWITCH_STANDARD_APP(trunk_inbound_function)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Inbound call on trunk %s, call:%s!\n", data, switch_core_session_get_uuid(session));
+ fs->OnCallNetworkIncoming(data, session);
+}
+
+//! Called if a call leaves FreeSWITCH via a gateway
+/*!
+ Called if a call leaves FreeSWITCH via a gateway. Outgoing CSTA Network interfaces should be defined in dialplan
+ default section with csta_trigger_trunk_outbound application triggered.
+ \param session The FreeSWITCH session
+ \param data The NID name set in dialplan (data parameter of csta_trigger_trunk_outbound application)
+
+ Example configuration:
+
+ <extension name="outbound_example">
+ <condition field="destination_number" expression="^20(.*)$">
+ <action application="csta_trigger_trunk_outbound" data="20"/>
+ <action application="set" data="effective_caller_id_number=193190"/>
+ <action application="bridge" data="sofia/gateway/example_gw/$1"/>
+ </condition>
+ </extension>
+
+ Note that NID name must only contain numeric characters to fit CSTA standard
+*/
+SWITCH_STANDARD_APP(trunk_outbound_function)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Outbound call on trunk %s, call:%s!\n", data, switch_core_session_get_uuid(session));
+ fs->OnCallNetworkOutgoing(data, session);
+}
+
+static void event_handler(switch_event_t *event)
+{
+
+ switch(event->event_id)
+ {
+ case SWITCH_EVENT_CUSTOM:
+ break;
+ case SWITCH_EVENT_CLONE:
+ break;
+ case SWITCH_EVENT_CHANNEL_CREATE:
+ fs->OnChannelCreate(event);
+ break;
+ case SWITCH_EVENT_CHANNEL_DESTROY:
+ break;
+ case SWITCH_EVENT_CHANNEL_STATE:
+ break;
+ case SWITCH_EVENT_CHANNEL_ANSWER:
+ fs->OnChannelAnswer(event);
+ break;
+ case SWITCH_EVENT_CHANNEL_HANGUP:
+ fs->OnChannelHangup(event);
+ break;
+ case SWITCH_EVENT_CHANNEL_EXECUTE:
+ case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE:
+ {
+ const char* app=switch_event_get_header(event, "Application");
+ if(app)
+ {
+ if(strcmp(app,"playback")==0)
+ fs->OnPlayback(event);
+ else
+ if(strcmp(app,"record")==0)
+ fs->OnRecord(event);
+ }
+ }
+ break;
+ case SWITCH_EVENT_CHANNEL_BRIDGE:
+ break;
+ case SWITCH_EVENT_CHANNEL_UNBRIDGE:
+ break;
+ case SWITCH_EVENT_CHANNEL_PROGRESS:
+ case SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA:
+ fs->OnProgress(event);
+ break;
+ case SWITCH_EVENT_CHANNEL_OUTGOING:
+ break;
+ case SWITCH_EVENT_CHANNEL_PARK:
+ break;
+ case SWITCH_EVENT_CHANNEL_UNPARK:
+ break;
+ case SWITCH_EVENT_CHANNEL_APPLICATION:
+ break;
+ case SWITCH_EVENT_CHANNEL_ORIGINATE:
+ break;
+ case SWITCH_EVENT_CHANNEL_UUID:
+ break;
+ case SWITCH_EVENT_API:
+ break;
+ case SWITCH_EVENT_LOG:
+ break;
+ case SWITCH_EVENT_INBOUND_CHAN:
+ break;
+ case SWITCH_EVENT_OUTBOUND_CHAN:
+ break;
+ case SWITCH_EVENT_STARTUP:
+ break;
+ case SWITCH_EVENT_SHUTDOWN:
+ break;
+ case SWITCH_EVENT_PUBLISH:
+ break;
+ case SWITCH_EVENT_UNPUBLISH:
+ break;
+ case SWITCH_EVENT_TALK:
+ break;
+ case SWITCH_EVENT_NOTALK:
+ break;
+ case SWITCH_EVENT_SESSION_CRASH:
+ break;
+ case SWITCH_EVENT_MODULE_LOAD:
+ break;
+ case SWITCH_EVENT_MODULE_UNLOAD:
+ break;
+ case SWITCH_EVENT_DTMF:
+ fs->OnDtmf(event);
+ break;
+ case SWITCH_EVENT_MESSAGE:
+ break;
+ case SWITCH_EVENT_PRESENCE_IN:
+ break;
+ case SWITCH_EVENT_NOTIFY_IN:
+ break;
+ case SWITCH_EVENT_PRESENCE_OUT:
+ break;
+ case SWITCH_EVENT_PRESENCE_PROBE:
+ break;
+ case SWITCH_EVENT_MESSAGE_WAITING:
+ break;
+ case SWITCH_EVENT_MESSAGE_QUERY:
+ break;
+ case SWITCH_EVENT_ROSTER:
+ break;
+ case SWITCH_EVENT_CODEC:
+ break;
+ case SWITCH_EVENT_BACKGROUND_JOB:
+ break;
+ case SWITCH_EVENT_DETECTED_SPEECH:
+ break;
+ case SWITCH_EVENT_DETECTED_TONE:
+ break;
+ case SWITCH_EVENT_PRIVATE_COMMAND:
+ break;
+ case SWITCH_EVENT_HEARTBEAT:
+ break;
+ case SWITCH_EVENT_TRAP:
+ break;
+ case SWITCH_EVENT_ADD_SCHEDULE:
+ break;
+ case SWITCH_EVENT_DEL_SCHEDULE:
+ break;
+ case SWITCH_EVENT_EXE_SCHEDULE:
+ break;
+ case SWITCH_EVENT_RE_SCHEDULE:
+ break;
+ case SWITCH_EVENT_RELOADXML:
+ break;
+ case SWITCH_EVENT_NOTIFY:
+ break;
+ case SWITCH_EVENT_SEND_MESSAGE:
+ break;
+ case SWITCH_EVENT_RECV_MESSAGE:
+ break;
+ case SWITCH_EVENT_REQUEST_PARAMS:
+ break;
+ case SWITCH_EVENT_CHANNEL_DATA:
+ break;
+ case SWITCH_EVENT_GENERAL:
+ break;
+ case SWITCH_EVENT_COMMAND:
+ break;
+ case SWITCH_EVENT_SESSION_HEARTBEAT:
+ break;
+ case SWITCH_EVENT_CLIENT_DISCONNECTED:
+ break;
+ case SWITCH_EVENT_SERVER_DISCONNECTED:
+ break;
+ case SWITCH_EVENT_SEND_INFO:
+ break;
+ case SWITCH_EVENT_RECV_INFO:
+ break;
+ }
+
+}
+
+
+static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
+{
+ THREAD_INFO* thread_info=(THREAD_INFO*)obj;
+
+ FreeSWITCHSocket socket(thread_info->socket,thread_info->pool );
+ XMLSession csta_session(platform, &socket, fs);
+
+ char remote_ip[50];
+ switch_sockaddr_t *sa;
+ switch_socket_addr_get(&sa, SWITCH_TRUE, thread_info->socket);
+ switch_get_addr(remote_ip, sizeof(remote_ip), sa);
+ if( (Config::Instance()->IsACLEnabled())
+ && (!switch_check_network_list_ip(remote_ip, Config::Instance()->GetACLName())) )
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", remote_ip, Config::Instance()->GetACLName());
+ UniversalErrorResponse err(0,error_type_security,genericError);
+ csta_session.SendMsg(&err);
+ socket.Close();
+ }
+ else
+ csta_session.Run();
+
+ delete thread_info;
+ return NULL;
+}
+
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_csta_socket_load)
+{
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+ switch_application_interface_t *app_interface;
+
+ fs=new FreeSWITCH(pool);
+ platform=new FreeSWITCHPlatform();
+
+ bRunning=true;
+ Config::Instance()->ReadConfig();
+
+ SWITCH_ADD_APP(app_interface, "csta_trigger_queue", "Notifies about call entered a CSTA queue", "Notifies CSTA module about a call entered a CSAT queue.", queue_function, "", SAF_SUPPORT_NOMEDIA);
+ SWITCH_ADD_APP(app_interface, "csta_trigger_trunk_inbound", "Notifies about call entering FreeSWITCH from outside", "Notifies CSTA module about about call entering FreeSWITCH from outside.", trunk_inbound_function, "", SAF_SUPPORT_NOMEDIA);
+ SWITCH_ADD_APP(app_interface, "csta_trigger_trunk_outbound", "Notifies about call leaving FreeSWITCH", "Notifies CSTA module about call leaving FreeSWITCH.", trunk_outbound_function, "", SAF_SUPPORT_NOMEDIA);
+
+ //TODO: filter events
+ if (switch_event_bind_removable(modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL, &node) != SWITCH_STATUS_SUCCESS)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind to events!\n");
+ return SWITCH_STATUS_GENERR;
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_csta_socket_shutdown)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting down..\n");
+ bRunning=false;
+ if(listen_socket)
+ {
+ switch_socket_shutdown(listen_socket, SWITCH_SHUTDOWN_READWRITE);
+ switch_socket_close(listen_socket);
+ listen_socket=NULL;
+ }
+
+ switch_event_unbind(&node);
+
+ delete fs;
+ delete platform;
+ fs=NULL;
+ platform=NULL;
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+
+SWITCH_MODULE_RUNTIME_FUNCTION(mod_csta_socket_runtime)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Starting..\n");
+
+ switch_status_t rv;
+
+ switch_sockaddr_t *sa;
+ switch_memory_pool_t *pool = NULL, *listener_pool = NULL;
+ switch_socket_t *inbound_socket = NULL;
+
+ if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_core_new_memory_pool failed.\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ rv = switch_sockaddr_info_get(&sa, Config::Instance()->GetListenAddress(), SWITCH_INET, Config::Instance()->GetXmlPort(), 0, pool);
+ if(rv)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_sockaddr_info_get failed.\n");
+ return SWITCH_STATUS_TERM;
+ }
+ rv = switch_socket_create(&listen_socket, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, pool);
+ if(rv)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_socket_create failed.\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ rv = switch_socket_opt_set(listen_socket, SWITCH_SO_REUSEADDR, 1);
+ if (rv)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_socket_opt_set failed.\n");
+ return SWITCH_STATUS_TERM;
+ }
+ rv = switch_socket_bind(listen_socket, sa);
+ if (rv)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_socket_bind failed.\n");
+ return SWITCH_STATUS_TERM;
+ }
+ rv = switch_socket_listen(listen_socket, 5);
+ if (rv)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "switch_socket_listen failed.\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "CSTA-XML socket up listening on %s:%u\n", Config::Instance()->GetListenAddress(),Config::Instance()->GetXmlPort());
+
+ while(bRunning)
+ {
+ if (switch_core_new_memory_pool(&listener_pool) != SWITCH_STATUS_SUCCESS)
+ {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ if ((rv = switch_socket_accept(&inbound_socket, listen_socket, listener_pool))) {
+ if (!bRunning) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Shutting Down\n");
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error\n");
+ }
+ break;
+ }
+
+
+ switch_thread_t *thread;
+ switch_threadattr_t *thd_attr = NULL;
+ THREAD_INFO * thread_info=new THREAD_INFO;
+ thread_info->socket=inbound_socket;
+ thread_info->pool=listener_pool;
+
+ switch_threadattr_create(&thd_attr, listener_pool);
+ switch_threadattr_detach_set(thd_attr, 1);
+ switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+ switch_thread_create(&thread, thd_attr, listener_run, thread_info, listener_pool);
+
+ }
+
+ if(listen_socket)
+ {
+ switch_socket_shutdown(listen_socket, SWITCH_SHUTDOWN_READWRITE);
+ //switch_socket_close(listen_socket);
+ listen_socket=NULL;
+ }
+
+ return SWITCH_STATUS_TERM;
+}
+
+
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/mod_csta_socket.def (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/mod_csta_socket.def 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,2 @@
+EXPORTS
+ mod_csta_socket_module_interface
\ No newline at end of file
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/mod_csta_socket.vcproj (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/mod_csta_socket.vcproj 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,353 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="9,00"
+ Name="FreeSWITCH_CSTA"
+ ProjectGUID="{05515420-16DE-4E63-B373-85BE859A5142}"
+ RootNamespace="mod_csta_socket"
+ Keyword="Win32Proj"
+ TargetFrameworkVersion="131072"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ <Platform
+ Name="x64"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\..\..\..\w32\module_Debug.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""..\..\..\..\..\src\include";"..\..\..\..\..\libs\include";..\CSTAInsideCore\include\csta;..\CSTAInsideCore\include"
+ UsePrecompiledHeader="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freeswitchcore.lib libapr-1.lib CSTAInsideCore.lib"
+ OutputFile="..\..\..\..\..\$(ConfigurationName)/mod/mod_csta_socket.dll"
+ AdditionalLibraryDirectories=""..\..\..\..\..\w32\library\$(ConfigurationName)\";"..\..\..\..\..\libs\win32\apr\$(ConfigurationName)\";..\CSTAInsideCore\lib\VC90"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\..\..\..\w32\module_Debug.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\..\..\..\w32\module_Release.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories=""..\..\..\..\..\src\include";"..\..\..\..\..\libs\include";..\CSTAInsideCore\include\csta;..\CSTAInsideCore\include"
+ UsePrecompiledHeader="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="freeswitchcore.lib libapr-1.lib CSTAInsideCore.lib"
+ OutputFile="..\..\..\..\..\$(ConfigurationName)/mod/mod_csta_socket.dll"
+ AdditionalLibraryDirectories=""..\..\..\..\..\w32\library\$(ConfigurationName)\";"..\..\..\..\..\libs\win32\apr\$(ConfigurationName)\";..\CSTAInsideCore\lib\VC90"
+ ModuleDefinitionFile="$(InputName).def"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|x64"
+ ConfigurationType="2"
+ InheritedPropertySheets="..\..\..\..\..\w32\module_Release.vsprops"
+ CharacterSet="2"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ TargetEnvironment="3"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="0"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(SolutionDir)$(PlatformName)\$(ConfigurationName)/mod/$(ProjectName).dll"
+ RandomizedBaseAddress="1"
+ DataExecutionPrevention="0"
+ TargetMachine="17"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Header Files"
+ >
+ <File
+ RelativePath=".\config.h"
+ >
+ </File>
+ <File
+ RelativePath=".\FreeSWITCH.h"
+ >
+ </File>
+ <File
+ RelativePath=".\FreeSWITCHPlatform.h"
+ >
+ </File>
+ <File
+ RelativePath=".\FreeSWITCHSocket.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Source Files"
+ >
+ <File
+ RelativePath=".\config.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\FreeSWITCH.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\FreeSWITCHPlatform.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\FreeSWITCHSocket.cpp"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath=".\FreeSWITCH_CSTA.rc"
+ >
+ </File>
+ <File
+ RelativePath=".\mod_csta_socket.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\mod_csta_socket.def"
+ >
+ </File>
+ <File
+ RelativePath=".\README"
+ >
+ </File>
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/resource.h (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/FreeSWITCH/resource.h 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,14 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by FreeSWITCH_CSTA.rc
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 101
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/mod_csta_socket.sln (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/mod_csta_socket.sln 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,37 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeSWITCH_CSTA", "FreeSWITCH\mod_csta_socket.vcproj", "{05515420-16DE-4E63-B373-85BE859A5142}"
+ ProjectSection(ProjectDependencies) = postProject
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD} = {4F92B672-DADB-4047-8D6A-4BB3796733FD}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download CSTAInside", "Download CSTAInside.vcproj", "{4F92B672-DADB-4047-8D6A-4BB3796733FD}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {05515420-16DE-4E63-B373-85BE859A5142}.Debug|Win32.ActiveCfg = Debug|Win32
+ {05515420-16DE-4E63-B373-85BE859A5142}.Debug|Win32.Build.0 = Debug|Win32
+ {05515420-16DE-4E63-B373-85BE859A5142}.Debug|x64.ActiveCfg = Debug|x64
+ {05515420-16DE-4E63-B373-85BE859A5142}.Debug|x64.Build.0 = Debug|x64
+ {05515420-16DE-4E63-B373-85BE859A5142}.Release|Win32.ActiveCfg = Release|Win32
+ {05515420-16DE-4E63-B373-85BE859A5142}.Release|Win32.Build.0 = Release|Win32
+ {05515420-16DE-4E63-B373-85BE859A5142}.Release|x64.ActiveCfg = Release|x64
+ {05515420-16DE-4E63-B373-85BE859A5142}.Release|x64.Build.0 = Release|x64
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|Win32.Build.0 = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Debug|x64.ActiveCfg = Debug|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.ActiveCfg = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|Win32.Build.0 = Release|Win32
+ {4F92B672-DADB-4047-8D6A-4BB3796733FD}.Release|x64.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
--- freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/util.vbs (rev 0)
+++ freeswitch/trunk/contrib/mod/event_handlers/mod_csta_socket/mod_csta_socket/util.vbs 2009-12-24 00:51:46 UTC (rev 16050)
@@ -0,0 +1,329 @@
+'
+' Contributor(s):
+' Michael Jerris <mike@jerris.com>
+' David A. Horner http://dave.thehorners.com
+'----------------------------------------------
+
+'On Error Resume Next
+' **************
+' Initialization
+' **************
+
+Set WshShell = CreateObject("WScript.Shell")
+Set FSO = CreateObject("Scripting.FileSystemObject")
+Set WshSysEnv = WshShell.Environment("SYSTEM")
+Set xml = CreateObject("Microsoft.XMLHTTP")
+Dim UseWgetEXE
+
+On Error Resume Next
+Set oStream = CreateObject("Adodb.Stream")
+On Error Goto 0
+
+If Not IsObject(oStream) Then
+ wscript.echo("Failed to create Adodb.Stream, using alternative download method.")
+ UseWgetEXE=true
+Else
+ UseWgetEXE=false
+End If
+Randomize
+Set objArgs = WScript.Arguments
+quote=Chr(34)
+ScriptDir=Left(WScript.ScriptFullName,Len(WScript.ScriptFullName)-Len(WScript.ScriptName))
+UtilsDir=Showpath(ScriptDir)
+ToolsBase="http://files.freeswitch.org/downloads/win32/"
+
+If UseWgetEXE Then
+ GetWgetEXE UtilsDir
+End If
+
+GetCompressionTools UtilsDir
+
+
+If objArgs.Count >=3 Then
+ Select Case objArgs(0)
+ Case "Get"
+ Wget objArgs(1), Showpath(objArgs(2))
+ Case "GetUnzip"
+ WgetUnCompress objArgs(1), Showpath(objArgs(2))
+ Case "Version"
+ 'CreateVersion(tmpFolder, VersionDir, includebase, includedest)
+ CreateVersion Showpath(objArgs(1)), Showpath(objArgs(2)), objArgs(3), objArgs(4)
+ End Select
+End If
+
+
+' *******************
+' Utility Subroutines
+' *******************
+
+
+Sub WgetUnCompress(URL, DestFolder)
+ If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If
+ StartPos = InstrRev(URL, "/", -1, 1)
+ strlength = Len(URL)
+ filename=Right(URL,strlength-StartPos)
+ NameEnd = InstrRev(filename, ".",-1, 1)
+ filestrlength = Len(filename)
+ filebase = Left(filename,NameEnd)
+ fileext = Right(filename, Len(filename) - NameEnd)
+ Wget URL, DestFolder
+ If fileext = "zip" Then
+ UnCompress Destfolder & filename, DestFolder & filebase
+ Else
+ UnCompress Destfolder & filename, DestFolder
+ End If
+End Sub
+
+Sub GetCompressionTools(DestFolder)
+ Dim oExec
+ If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If
+ If Not FSO.FileExists(DestFolder & "7za.exe") Then
+ If Not FSO.FileExists(DestFolder & "7za.tag") Then
+ Set MyFile = fso.CreateTextFile(DestFolder & "7za.tag", True)
+ MyFile.WriteLine("This file marks a pending download for 7za.exe so we don't download it twice at the same time")
+ MyFile.Close
+
+ Wget ToolsBase & "7za.exe", DestFolder
+
+ FSO.DeleteFile DestFolder & "7za.tag" ,true
+ Else
+ WScript.Sleep(5000)
+ End If
+ End If
+End Sub
+
+Sub GetWgetEXE(DestFolder)
+ Dim oExec
+ If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If
+ If Not FSO.FileExists(DestFolder & "wget.exe") Then
+ Slow_Wget ToolsBase & "wget.exe", DestFolder
+ End If
+End Sub
+
+Sub UnCompress(Archive, DestFolder)
+ batname = "tmp" & CStr(Int(10000*Rnd)) & ".bat"
+ wscript.echo("Extracting: " & Archive)
+ Set MyFile = fso.CreateTextFile(UtilsDir & batname, True)
+ MyFile.WriteLine("@" & quote & UtilsDir & "7za.exe" & quote & " x " & quote & Archive & quote & " -y -o" & quote & DestFolder & quote )
+ MyFile.Close
+ Set oExec = WshShell.Exec(UtilsDir & batname)
+ Do
+ WScript.Echo OExec.StdOut.ReadLine()
+ Loop While Not OExec.StdOut.atEndOfStream
+ If FSO.FileExists(Left(Archive, Len(Archive)-3))Then
+ Set MyFile = fso.CreateTextFile(UtilsDir & batname, True)
+ MyFile.WriteLine("@" & quote & UtilsDir & "7za.exe" & quote & " x " & quote & Left(Archive, Len(Archive)-3) & quote & " -y -o" & quote & DestFolder & quote )
+ MyFile.Close
+ Set oExec = WshShell.Exec(UtilsDir & batname)
+ Do
+ WScript.Echo OExec.StdOut.ReadLine()
+ Loop While Not OExec.StdOut.atEndOfStream
+ WScript.Sleep(500)
+ FSO.DeleteFile Left(Archive, Len(Archive)-3) ,true
+ End If
+ If FSO.FileExists(Left(Archive, Len(Archive)-3) & "tar")Then
+ Set MyFile = fso.CreateTextFile(UtilsDir & batname, True)
+ MyFile.WriteLine("@" & quote & UtilsDir & "7za.exe" & quote & " x " & quote & Left(Archive, Len(Archive)-3) & "tar" & quote & " -y -o" & quote & DestFolder & quote )
+ MyFile.Close
+ Set oExec = WshShell.Exec(UtilsDir & batname)
+ Do
+ WScript.Echo OExec.StdOut.ReadLine()
+ Loop While Not OExec.StdOut.atEndOfStream
+ WScript.Sleep(500)
+ FSO.DeleteFile Left(Archive, Len(Archive)-3) & "tar",true
+ End If
+
+ WScript.Sleep(500)
+ If FSO.FileExists(UtilsDir & batname)Then
+ FSO.DeleteFile UtilsDir & batname, True
+ End If
+End Sub
+
+Sub Wget(URL, DestFolder)
+ StartPos = InstrRev(URL, "/", -1, 1)
+ strlength = Len(URL)
+ filename=Right(URL,strlength-StartPos)
+ If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If
+
+ Wscript.echo("Downloading: " & URL)
+
+If UseWgetEXE Then
+ batname = "tmp" & CStr(Int(10000*Rnd)) & ".bat"
+ Set MyFile = fso.CreateTextFile(UtilsDir & batname, True)
+ MyFile.WriteLine("@cd " & quote & DestFolder & quote)
+ MyFile.WriteLine("@" & quote & UtilsDir & "wget.exe" & quote & " " & URL)
+ MyFile.Close
+ Set oExec = WshShell.Exec(UtilsDir & batname)
+ Do
+ WScript.Echo OExec.StdOut.ReadLine()
+ Loop While Not OExec.StdOut.atEndOfStream
+
+Else
+ xml.Open "GET", URL, False
+ xml.Send
+
+ Const adTypeBinary = 1
+ Const adSaveCreateOverWrite = 2
+ Const adSaveCreateNotExist = 1
+
+ oStream.type = adTypeBinary
+ oStream.open
+ oStream.write xml.responseBody
+ oStream.savetofile DestFolder & filename, adSaveCreateOverWrite
+ oStream.close
+End If
+
+End Sub
+
+Sub Slow_Wget(URL, DestFolder)
+ StartPos = InstrRev(URL, "/", -1, 1)
+ strlength = Len(URL)
+ filename=Right(URL,strlength-StartPos)
+ If Right(DestFolder, 1) <> "\" Then DestFolder = DestFolder & "\" End If
+
+ Wscript.echo("Downloading: " & URL)
+ xml.Open "GET", URL, False
+ xml.Send
+
+ const ForReading = 1 , ForWriting = 2 , ForAppending = 8
+Set MyFile = fso.OpenTextFile(DestFolder & filename ,ForWriting, True)
+For i = 1 to lenb(xml.responseBody)
+ MyFile.write Chr(Ascb(midb(xml.responseBody,i,1)))
+Next
+MyFile.Close()
+
+End Sub
+
+Function Showpath(folderspec)
+ Set f = FSO.GetFolder(folderspec)
+ showpath = f.path & "\"
+End Function
+
+
+Function FindVersionStringInConfigure(strConfigFile, strVersionString)
+
+Set objRegEx = CreateObject("VBScript.RegExp")
+objRegEx.Pattern = "[^#]AC_SUBST\(" & strVersionString & ".*\[([^\[]*)\]"
+
+Set objFSO = CreateObject("Scripting.FileSystemObject")
+Set objFile = objFSO.OpenTextFile(strConfigFile, 1)
+strSearchString = objFile.ReadAll
+objFile.Close
+
+Set colMatches = objRegEx.Execute(strSearchString)
+
+strResult = ""
+If colMatches.Count > 0 Then
+ For Each strMatch in colMatches
+ strResult = objRegEx.Replace(strMatch.Value, "$1")
+ Next
+End If
+
+ FindVersionStringInConfigure = strResult
+
+End Function
+
+Sub FindReplaceInFile(FileName, sFind, sReplace)
+ Const OpenAsASCII = 0 ' Opens the file as ASCII (TristateFalse)
+ Const OpenAsUnicode = -1 ' Opens the file as Unicode (TristateTrue)
+ Const OpenAsDefault = -2 ' Opens the file using the system default
+
+ Const OverwriteIfExist = -1
+ Const FailIfNotExist = 0
+ Const ForReading = 1
+
+ Set fOrgFile = FSO.OpenTextFile(FileName, ForReading, FailIfNotExist, OpenAsASCII)
+ sText = fOrgFile.ReadAll
+ fOrgFile.Close
+ sText = Replace(sText, sFind, sReplace)
+ Set fNewFile = FSO.CreateTextFile(FileName, OverwriteIfExist, OpenAsASCII)
+ fNewFile.WriteLine sText
+ fNewFile.Close
+End Sub
+
+Sub CreateVersion(tmpFolder, VersionDir, includebase, includedest)
+ Dim oExec
+
+ strVerMajor = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_MAJOR")
+ strVerMinor = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_MINOR")
+ strVerMicro = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_MICRO")
+ strVerRev = FindVersionStringInConfigure(VersionDir & "configure.in", "SWITCH_VERSION_REVISION")
+
+ If Right(tmpFolder, 1) <> "\" Then tmpFolder = tmpFolder & "\" End If
+ If Not FSO.FileExists(tmpFolder & "fs_svnversion.exe") Then
+ Wget ToolsBase & "fs_svnversion.exe", tmpFolder
+ End If
+
+ If Not FSO.FileExists(tmpFolder & "libdb44.dll") Then
+ Wget ToolsBase & "libdb44.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "libsvn_diff-1.dll") Then
+ Wget ToolsBase & "libsvn_diff-1.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "libsvn_subr-1.dll") Then
+ Wget ToolsBase & "libsvn_subr-1.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "libsvn_wc-1.dll") Then
+ Wget ToolsBase & "libsvn_wc-1.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "intl3_svn.dll") Then
+ Wget ToolsBase & "intl3_svn.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "libapr-1.dll") Then
+ Wget ToolsBase & "libapr-1.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "libaprutil-1.dll") Then
+ Wget ToolsBase & "libaprutil-1.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "libapriconv-1.dll") Then
+ Wget ToolsBase & "libapriconv-1.dll", tmpFolder
+ End If
+ If Not FSO.FileExists(tmpFolder & "libsvn_delta-1.dll") Then
+ Wget ToolsBase & "libsvn_delta-1.dll", tmpFolder
+ End If
+
+ Dim sLastFile
+ Const OverwriteIfExist = -1
+ Const ForReading = 1
+
+ if strVerRev = "" Then
+ VersionCmd="fs_svnversion " & quote & VersionDir & "." & quote & " -n"
+ Set MyFile = fso.CreateTextFile(tmpFolder & "tmpVersion.Bat", True)
+ MyFile.WriteLine("@" & "cd " & quote & tmpFolder & quote )
+ MyFile.WriteLine("@" & VersionCmd)
+ MyFile.Close
+ Set oExec = WshShell.Exec("cmd /C " & quote & tmpFolder & "tmpVersion.Bat" & quote)
+ Do
+ strFromProc = OExec.StdOut.ReadLine()
+ VERSION=strFromProc
+ Loop While Not OExec.StdOut.atEndOfStream
+ sLastVersion = ""
+ Set sLastFile = FSO.OpenTextFile(tmpFolder & "lastversion", ForReading, true, OpenAsASCII)
+ If Not sLastFile.atEndOfStream Then
+ sLastVersion = sLastFile.ReadLine()
+ End If
+ sLastFile.Close
+ End If
+
+ if strVerRev <> "" Then
+ VERSION = strVerRev
+ End If
+
+ If VERSION = "" Then
+ VERSION = "UNKNOWN"
+ End If
+
+ If VERSION <> sLastVersion Then
+ Set MyFile = fso.CreateTextFile(tmpFolder & "lastversion", True)
+ MyFile.WriteLine(VERSION)
+ MyFile.Close
+
+ FSO.CopyFile includebase, includedest, true
+ FindReplaceInFile includedest, "@SWITCH_VERSION_REVISION@", VERSION
+ FindReplaceInFile includedest, "@SWITCH_VERSION_MAJOR@", strVerMajor
+ FindReplaceInFile includedest, "@SWITCH_VERSION_MINOR@", strVerMinor
+ FindReplaceInFile includedest, "@SWITCH_VERSION_MICRO@", strVerMicro
+
+ End If
+
+End Sub