www.pudn.com > TsapiCallRouting.rar > CallRoutingDlg.cpp
// CallRoutingDlg.cpp : implementation file
//
#include "stdafx.h"
#include "resource.h" // replace with theApp header if needed
#include "CallRoutingDlg.h"
#include "opentsrv.h"
#include "utilities.h"
// For non-MFC folks, this map replaces the large "switch" statement found in
// straight C Windows programs. The ON_MESSAGE() lines were added manually.
// Read them as "when a message of type {first argument} is received, call
// the method {second argument}"
BEGIN_MESSAGE_MAP(CallRoutingDlg, CDialog)
ON_MESSAGE(WM_TSAPICSTACONFIRMATION, OnTsapiCstaConfirmation)
ON_MESSAGE(WM_TSAPICSTAUNSOLICITED, OnTsapiCstaUnsolicited)
ON_MESSAGE(WM_TSAPICSTAREQUEST, OnTsapiCstaRequest)
//{{AFX_MSG_MAP(CallRoutingDlg)
/*
ON_BN_CLICKED(IDC_CALL, OnCall)
ON_BN_CLICKED(IDC_HANGUP, OnHangup)
ON_EN_CHANGE(IDC_TODEVICEID, OnChangeTodeviceid)
*/
ON_WM_TIMER()
//}}AFX_MSG_MAP
//ON_LBN_SELCHANGE(IDC_LOGLIST, &CallRoutingDlg::OnLbnSelchangeLoglist)
ON_BN_CLICKED(IDC_ADD, &CallRoutingDlg::OnBnClickedAdd)
ON_BN_CLICKED(IDC_DELETE, &CallRoutingDlg::OnBnClickedDelete)
ON_BN_CLICKED(IDC_MOVEUP, &CallRoutingDlg::OnBnClickedMoveup)
ON_BN_CLICKED(IDC_MOVEDOWN, &CallRoutingDlg::OnBnClickedMovedown)
ON_BN_CLICKED(IDC_SET, &CallRoutingDlg::OnBnClickedSet)
ON_NOTIFY(LVN_ITEMCHANGED, IDC_RULE_LIST, &CallRoutingDlg::OnLvnItemchangedRuleList)
ON_NOTIFY(NM_CLICK, IDC_RULE_LIST, &CallRoutingDlg::OnNMClickRuleList)
END_MESSAGE_MAP()
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CallRoutingDlg dialog
CallRoutingDlg::CallRoutingDlg(CWnd* pParent /*=NULL*/)
: CDialog(CallRoutingDlg::IDD, pParent)
, m_lowerBound(_T(""))
, m_upperBound(_T(""))
, m_destination(_T(""))
, m_DefaultRoute(_T(""))
, m_UUMessage(_T(""))
{
//{{AFX_DATA_INIT(CallRoutingDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_TsapiWndPtr = 0;
m_CallHandle = 0;
routeRegisterReqID = 0;
item =0;
ruleItem =0;
// m_LogListControl.InsertColumn( LOG_DIRECTION, "Time",
// LVCFMT_LEFT, 50, LOG_DIRECTION);
// UpdateData(FALSE);
}
// For non-MFC folks, this is a helper routine for passing data back-and-forth
// from this class to the Open Tserver dialog.
void CallRoutingDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(COpenTsrv)
DDX_Control(pDX, IDC_LOGLIST, m_LogListControl);
//}}AFX_DATA_MAP
DDX_Text(pDX, IDC_EDIT1, m_lowerBound);
DDX_Text(pDX, IDC_EDIT2, m_upperBound);
DDX_Control(pDX, IDC_EDIT1, m_lowerBoundControl);
DDX_Control(pDX, IDC_EDIT2, m_upperBoundControl);
DDV_MaxChars(pDX, m_lowerBound, 7);
DDX_Control(pDX, IDC_EDIT3, m_destinationControl);
DDX_Text(pDX, IDC_EDIT3, m_destination);
DDV_MaxChars(pDX, m_destination, 10);
DDX_Control(pDX, IDC_RULE_LIST, m_RuleListControl);
DDX_Control(pDX, IDC_EDIT4, m_DefaultRouteControl);
DDX_Text(pDX, IDC_EDIT4, m_DefaultRoute);
DDV_MaxChars(pDX, m_DefaultRoute, 10);
DDX_Control(pDX, IDC_EDIT5, m_UUMessageControl);
DDX_Text(pDX, IDC_EDIT5, m_UUMessage);
}
CallRoutingDlg::~CallRoutingDlg()
{
// delete the hidden TSAPI window
if(m_TsapiWndPtr)
{
delete m_TsapiWndPtr;
}
}
/////////////////////////////////////////////////////////////////////////////
// CallRoutingDlg message handlers
BOOL CallRoutingDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// setting a timer allows the dialog to be displayed before initialization is
// completed - the init will be completed when the timer fires.
if(!SetTimer(1, 1, NULL))
{
// if the timer can't be set, just call the OnTimer() method manually so
// initialization can complete.
OnTimer(1);
}
return TRUE; // return TRUE unless you set the focus to a control
}
void CallRoutingDlg::OnTimer(UINT nIDEvent)
{
// finish initialization...
// ok to kill the timer even if it wasn't active (i.e. in the failure case from
// OnInitDialog().
KillTimer(nIDEvent);
// the class that calls COpenTsrv's DoModal() method is responsible
// for the CTsapiWnd object that will be created. It will be this
// classes responsibility to handle CTsapiWnd memory clean-up (delete
// the CTsapiWnd object) and also this classes responsibility to decide
// what to do on failures of the TSAPI stream.
COpenTsrv openDlg;
openDlg.m_TsapiController = (CWnd*)this;
if(openDlg.DoModal() != IDOK)
{
PostMessage(WM_COMMAND, IDCANCEL, 0);
return;
}
// retrieve the specified device to be monitored and the hidden TSAPI window
m_TsapiWndPtr = openDlg.m_TsapiWndPtr;
m_LogListControl.InsertColumn( LOG_TIME, "TIME", LVCFMT_LEFT, 185, LOG_TIME);
m_LogListControl.InsertColumn( LOG_MESSAGE, "LOG MESSAGE", LVCFMT_LEFT, 585, LOG_MESSAGE);
m_RuleListControl.InsertColumn(RULE_NUMBER, "Rule #", LVCFMT_LEFT, 60, LOWER_BOUND);
m_RuleListControl.InsertColumn(LOWER_BOUND, "From", LVCFMT_LEFT, 73, LOWER_BOUND);
m_RuleListControl.InsertColumn( UPPER_BOUND, "To ", LVCFMT_LEFT, 73, UPPER_BOUND);
m_RuleListControl.InsertColumn( DESTINATION, "Destination ", LVCFMT_LEFT,75, DESTINATION);
TO_MESSAGE_WINDOW("Registering this application as "+g_vdn+" router");
RegisterRoutingServer(g_vdn.GetString());
UpdateRuleList();
char buff[11];
_ultoa_s(g_defaultRoute,buff,10);
m_DefaultRoute.SetString(buff);
m_UUMessage.SetString(g_appendString);
UpdateData(FALSE);
CDialog::OnTimer(nIDEvent);
}
LRESULT CallRoutingDlg::OnTsapiCstaConfirmation(WPARAM wParam, LPARAM lParam)
{
// this dialog should either get a monitor conf event or
// a universal failure event
switch(m_TsapiWndPtr->m_EventBufPtr->eventHeader.eventType)
{
case CSTA_ROUTE_REGISTER_REQ_CONF:
{
routeRegistrationSuccessful = true;
CSTAConfirmationEvent * pUns = &(m_TsapiWndPtr->m_EventBufPtr->event.cstaConfirmation);
routeRegisterReqID = pUns->u.routeRegister.registerReqID;
// AfxMessageBox("Routing Confirmed");
TO_MESSAGE_WINDOW("Received CSTA_ROUTE_REGISTER_REQ_CONF. Registration confirmed");
}
break;
case CSTA_MONITOR_CONF:
// this is what we want...
break;
case CSTA_UNIVERSAL_FAILURE_CONF:
// failure for some reason. failure codes are listed in cstadefs.h.
if(routeRegistrationSuccessful)
cstaRouteRegisterCancel(m_TsapiWndPtr->m_AcsHandle, (InvokeID_t) this,routeRegisterReqID, NULL);
acsAbortStream(m_TsapiWndPtr->m_AcsHandle, NULL);
delete m_TsapiWndPtr;
m_TsapiWndPtr = 0;
AfxMessageBox("monitor device failed");
return 0;
case CSTA_ROUTE_REQUEST:
AfxMessageBox("CSTA_ROUTE_REQUEST");
break;
default:
if(routeRegistrationSuccessful)
cstaRouteRegisterCancel(m_TsapiWndPtr->m_AcsHandle, (InvokeID_t) this,routeRegisterReqID, NULL);
acsAbortStream(m_TsapiWndPtr->m_AcsHandle, NULL);
delete m_TsapiWndPtr;
m_TsapiWndPtr = 0;
AfxMessageBox("unexpected response to cstaMonitorDevice");
return 0;
}
// now the open tserver dialog can be dismissed.
// The calling class is now responsible for the CTsapiWnd memory clean-up
return 0;
}
LRESULT CallRoutingDlg::RegisterRoutingServer(const char * device)
{
//An application may be a routing server for more that one routing device. However,
// for a specific routing device, the G3PD allows only one application registered as the
// routing server. If a routing device already has a routing server registered, subsequent
// cstaRouteRegisterReq() requests will be negatively acknowledged.
routeRegistrationSuccessful = false;
DeviceID_t vdnDevice;
lstrcpy( vdnDevice, device);
RetCode_t rc = cstaRouteRegisterReq(m_TsapiWndPtr->m_AcsHandle,(InvokeID_t)this, &vdnDevice,0);
if(rc < 0)
{
// failure for some reason, specified in rc as a RetCode_t (defined in acs.h).
rc = acsAbortStream(m_TsapiWndPtr->m_AcsHandle, NULL);
delete m_TsapiWndPtr;
m_TsapiWndPtr = 0;
TO_MESSAGE_WINDOW("Failed to register for the events");
AfxMessageBox("cstaRouteRegisterReq failed. Restart TSAPI CallRouting server");
return 0;
}
return 0;
}
LRESULT CallRoutingDlg::OnTsapiCstaUnsolicited(WPARAM wParam, LPARAM lParam)
{
// Get the device record pointer out of the lParam
// Get the unsolicited event pointer out of the event buffer (for
// code efficiency and typing efficiency)
CTsapiDevice* pTsapi = (CTsapiDevice*)lParam;
CSTAUnsolicitedEvent* pUns = &(m_TsapiWndPtr->m_EventBufPtr->event.cstaUnsolicited);
switch(m_TsapiWndPtr->m_EventBufPtr->eventHeader.eventType)
{
// this is not a call-control event. just end the app if the monitor
// of the device was terminated for any reason.
case CSTA_MONITOR_ENDED:
AfxMessageBox("monitor failure");
PostMessage(WM_COMMAND, IDCANCEL, 0);
return 0;
// these are call-control events...
case CSTA_SERVICE_INITIATED: // null -> initiated (LOCAL only)
{
break;
}
case CSTA_ORIGINATED: // null/initiated -> connected (LOCAL only)
{
break;
}
case CSTA_DELIVERED: // null -> alerting
{
break;
}
case CSTA_NETWORK_REACHED: // null -> connected (REMOTE only)
{
break;
}
case CSTA_ESTABLISHED: // alerting/connected -> connected
{
break;
}
case CSTA_CALL_CLEARED: // * -> null (for all connections in call)
{
break;
}
case CSTA_CONNECTION_CLEARED: // * -> null
{
break;
}
default:
// unhandled message - ignore it
return 0;
}
// update the status of buttons and fields
// update the contents of fields
UpdateData(FALSE);
return 0;
}
LRESULT CallRoutingDlg::OnTsapiCstaRequest(WPARAM wParam, LPARAM lParam)
{
static char func[]="CallRoutingDlg::OnTsapiCstaRequest";
CSTARequestEvent * pUns = &(m_TsapiWndPtr->m_EventBufPtr->event.cstaRequest);
//AfxMessageBox("Route Request received");
switch(m_TsapiWndPtr->m_EventBufPtr->eventHeader.eventType) {
case CSTA_ROUTE_REQUEST:
{
CSTARouteRequestEvent_t *routeRequest = &(pUns->u.routeRequest);
break;
}
case CSTA_RE_ROUTE_REQUEST:
{
RoutingCrossRefID_t routingCrossRefID;
CSTAReRouteRequest_t *reRouteRequest = &(pUns->u.reRouteRequest);
routingCrossRefID = reRouteRequest->routingCrossRefID;
DeviceID_t device;
char message[100];
RetCode_t rc;
sprintf(device,"%d",g_defaultRoute);
rc = cstaRouteSelectInv(
m_TsapiWndPtr->m_AcsHandle,
(InvokeID_t)this, // Version 2
routeRegisterReqID,
routingCrossRefID,
&device,
0,
0,
0,
0 // no privateData buffer here
);
sprintf(message, "Reroute request received. Sending to default route %d",g_defaultRoute);
TO_MESSAGE_WINDOW(message);
DBG1_OUT(func,"%s",message);
}
break;
case CSTA_ROUTE_REQUEST_EXT:
{
//We need to obtain this handle from the
// event and use that handle to re route the call
RoutingCrossRefID_t routingCrossRefID;
CSTARouteRequestExtEvent_t *routeRequestExt = &(pUns->u.routeRequestExt);
routingCrossRefID = routeRequestExt->routingCrossRefID;
//get calling device id
CallingDeviceID_t * callingDeviceID = &(routeRequestExt->callingDevice);
//get called device id
CalledDeviceID_t * deviceID = &(routeRequestExt->currentRoute);
// SetUpValues_t *setupValue = & (routeRequestExt->setupInformation);
if ( m_TsapiWndPtr->m_AttPrivateData.length > 0 )
{
//get user dialed digits (CollectDigits setup from vector)
char *data = m_TsapiWndPtr->m_AttEvent.u.routeRequest.userEnteredCode.data;
char buffer[100];
memset(buffer, 0, sizeof(buffer));
switch (m_TsapiWndPtr->m_AttEvent.eventType)
{
case ATT_ROUTE_REQUEST:
{
char message[100];
int acctNum = atoi(data);
DeviceID_t device;
ATTPrivateData_t privateData;
RetCode_t rc;
sprintf(message,"Received CSTA_ROUTE_REQUEST_EXT. Calling Device %s Account Number %s",callingDeviceID->deviceID,data);
TO_MESSAGE_WINDOW(message);
DBG1_OUT( func, "%s", message);
//In this case the message tye is ASCII.
// strcpy(buffer,data);
//strcat(buffer,g_appendString);
if(g_appendString.GetLength() > 0)
{
ATTUserToUserInfo_t userInfo;
userInfo.type = UUI_IA5_ASCII;
strcpy(buffer,g_appendString);
userInfo.data.length = strlen(buffer);
(void)strcpy((char *)userInfo.data.value,buffer);
//The private data version we are using is V7
//create the private data structure with the UUI data
rc = attV7RouteSelect(&privateData, 0, 0, false, 0,0,0,&userInfo, (ATTRedirectType_t )g_callRoutingType);
} else
{
rc = attV7RouteSelect(&privateData, 0, 0, false, 0,0,0,0, (ATTRedirectType_t )g_callRoutingType);
}
if(rc < 0)
{
// failure for some reason, specified in rc as a RetCode_t (defined in acs.h).
sprintf(message,"Failed to Initiate private data attV7RouteSelect");
DBG1_OUT( func, message);
TO_MESSAGE_WINDOW(message);
return 0;
}
//get the route information from rule database.
int deviceId = getRoute(acctNum);
sprintf(device,"%d",deviceId);
//Route the call for according to the selected route
rc = cstaRouteSelectInv(
m_TsapiWndPtr->m_AcsHandle,
(InvokeID_t)this, // Version 2
routeRegisterReqID,
routingCrossRefID,
&device,
0,
0,
0,
(PrivateData_t *)&privateData // pass a pointer to the privateData buffer here
);
if(rc == 0)
sprintf(message,"Routed incoming call from %s to %d\0", callingDeviceID->deviceID,deviceId);
else
sprintf(message, "Failed to Route incoming call from %s to %d\0", callingDeviceID->deviceID,deviceId);
DBG1_OUT( func, "%s", message);
TO_MESSAGE_WINDOW(message);
break;
}
case ATTV5_ROUTE_REQUEST:
break;
default:
break;
}
}
}
break;
default:
break;
}
return 0;
}
void CallRoutingDlg::toMessageWindow(CString message)
{
char timeStamp[50];
int nIndex = m_LogListControl.InsertItem(item++,TimeStamp(timeStamp));
m_LogListControl.SetItemText(nIndex,LOG_MESSAGE,message.GetString());
}
int CallRoutingDlg::getRoute(int account) {
int i = 0;
for(rulesIt = rules.begin(); rulesIt != rules.end(); i++, rulesIt++)
{
if(((CRule)*rulesIt).belongs(account)) {
char message[200];
char ruleBuff[100];
((CRule)*rulesIt).toString(ruleBuff);
sprintf(message, "Rule %d [ %s ] matched", i, ruleBuff);
TO_MESSAGE_WINDOW(message);
return (((CRule)*rulesIt).getRoute());
}
}
TO_MESSAGE_WINDOW("No Rule Matched. Sending to Default Route "+g_defaultRoute);
return g_defaultRoute;
}
void CallRoutingDlg::OnBnClickedAdd()
{
UpdateData(TRUE);
// TODO: Add your control notification handler code here
int lb = atoi((const char *) m_lowerBound.GetString());
int up = atoi((const char * )m_upperBound.GetString());
int dest = atoi((const char * )m_destination.GetString());
CRule r(lb,up,dest);
rules.push_back(r);
char temp[50];
char message[100];
r.toString(temp);
sprintf(message, "New Rule %d Added [ %s ] ",(rules.size()-1),r.toString( temp));
TO_MESSAGE_WINDOW(message);
UpdateRuleList();
}
void CallRoutingDlg::OnBnClickedDelete()
{
// TODO: Add your control notification handler code here
UINT position = GetSelectedRuleNumber();
DeleteRule(position) ;
char message[100];
sprintf(message, "Rule %d deleted ", position);
TO_MESSAGE_WINDOW(message);
UpdateRuleList();
}
void CallRoutingDlg::UpdateRuleList() {
m_RuleListControl.DeleteAllItems();
ruleItem =1;
for(rulesIt = rules.begin(); rulesIt != rules.end(); rulesIt++)
{
CRule r = ((CRule)*rulesIt);
char buff[50];
_ultoa_s(ruleItem,buff,10);
int nIndex = m_RuleListControl.InsertItem(ruleItem++, buff);
_ultoa_s(r.getLowerBound(),buff,10);
m_RuleListControl.SetItemText(nIndex,LOWER_BOUND, buff);
_ultoa_s(r.getUpperBound(),buff,10);
m_RuleListControl.SetItemText(nIndex,UPPER_BOUND, buff);
_ultoa_s(r.getRoute(),buff,10);
m_RuleListControl.SetItemText(nIndex,DESTINATION, buff);
}
// m_LogListControl.SetItemText(nIndex,LOG_MESSAGE,message.GetString());
}
void CallRoutingDlg::OnBnClickedMoveup()
{
//m_RuleListControl.GetSelectedColumn
// TODO: Add your control notification handler code here
UINT position = GetSelectedRuleNumber();
if(position > 1) {
ChangeRulePosition(position, (position -1), false);
char message[100];
sprintf(message, "Rule %d moved to %d ", position, (position -1));
TO_MESSAGE_WINDOW(message);
}
}
void CallRoutingDlg::OnBnClickedMovedown()
{
// TODO: Add your control notification handler code here
UINT position = GetSelectedRuleNumber();
if(position < rules.size()) {
ChangeRulePosition(position, (position + 1), true);
char message[100];
sprintf(message, "Rule %d moved to %d ", position, (position + 1));
TO_MESSAGE_WINDOW(message);
}
}
void CallRoutingDlg::OnBnClickedSet()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE);
g_appendString.SetString(m_UUMessage);
g_defaultRoute = atoi((const char *)m_DefaultRoute.GetString());
}
UINT CallRoutingDlg::GetSelectedRuleNumber() {
static char func[] = "CallRoutingDlg::GetSelectedRuleNumber";
CString text;
LV_ITEM lvItem;
lvItem.iItem = m_RuleListControl.GetNextItem(-1, LVNI_ALL | LVNI_SELECTED);
lvItem.iSubItem = 0;
lvItem.mask = LVIF_PARAM;
if ( m_RuleListControl.GetItem(&lvItem) )
{
// we got it ... now set the "To" device ID to what is stored in the LOG_DEVICEID field
text = m_RuleListControl.GetItemText(lvItem.iItem, RULE_NUMBER);
}
DBG3_OUT (func, "Selected text [%d]", atoi((const char *)text));
return (atoi((const char *)text));
}
void CallRoutingDlg::OnLvnItemchangedRuleList(NMHDR *pNMHDR, LRESULT *pResult)
{
}
void CallRoutingDlg::OnNMClickRuleList(NMHDR *pNMHDR, LRESULT *pResult)
{
static char func[] = "CallRoutingDlg::OnNMClickRuleList";
LPNMLISTVIEW pNMLV = reinterpret_cast(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
}
void CallRoutingDlg::DeleteRule(UINT position)
{
int i;
rulesIt = rules.begin();
for(i =0; rulesIt != rules.end(); i++,rulesIt++)
{
if(i < position) {
continue;
} else if (i == position) {
rules.erase(rulesIt);
break;
} else {
break;
}
}
}
void CallRoutingDlg::ChangeRulePosition(int currentPosition, int newPosition, bool down)
{
int i;
rulesIt = rules.begin();
CRule r = rulesIt[currentPosition -1];
vector::iterator newPositionIt;
for(i =1; rulesIt != rules.end(); i++,rulesIt++)
{
if(i < currentPosition) {
newPositionIt = rulesIt;
continue;
} else if (i == currentPosition) {
rules.erase(rulesIt);
if(down)
newPositionIt = ++rulesIt;
rules.insert(newPositionIt,r);
break;
} else {
break;
}
}
UpdateRuleList();
}