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(); 
}