📄 directorynumber.cpp
字号:
// DirectoryNumber.cpp : Implementation of CDirectoryNumber
#include "stdafx.h"
#include "resource.h"
#include "ctcv4.h"
#include "KVPair.h"
#include "KVList.h"
#include "CTIEvent.h"
#include "MichelleCTI.h"
#include "DirectoryNumber.h"
#include <ctc_rpc.h>
#include <math.h>
#include <list>
using namespace std;
#define TIME_WAIT_API 60*1000 // max time of waiting api reply to dn default handler
#define TIME_WAIT_MESSAGE 60*1000 // max time of waiting incoming event
#define MAX_STEP_COUNT 1 // the max search step in the state map
// This number should >=1, and not be too big
DECLARE_CASTER(CKVList, IKVList)
extern void WriteLog(char* pData);
extern BOOL B2C(BSTR bStr,char* pStr,int nBufLen);
extern HWND h_gPumpWnd; // The main window message process
extern HINSTANCE h_gInstance; // the dll instance handle
/////////////////////////////////////////////////////
// The telephone state convert table
//Convert to Active Deliver Hold Null/Initiate Receive Unknown error
//Active -1 -1 TpSuspended TpDisconnected -1 -1 -1
//Deliver OpAnswered -1 -1 TpDisconnected -1 ctcK_Other -1
//Hold TpRetrieved -1 -1 -1 -1 -1 -1
//Null/Initiate -1 Destseized -1 ctcK_Offhook InboundCall -1 -1
//Receive TpAnswered -1 -1 -1 -1 -1 -1
//Unknown Any Any Any Any Any Any Any
//error Any Any Any Any Any Any -1
/////////////MARK by rick --begin
//enum PHONE_STATE
//{
// CTC_NULL=3, // means this state's index in this table
// CTC_INITIAL=3,
// CTC_ACTIVE=0,
// CTC_DELIVER=1,
// CTC_RECEIVE=4,
// CTC_HOLD=2,
// CTC_ERROR=5
//};
/////////////MARK --end
// The telephone sate convert table, -1 means no routine, other means a event which
// causing this transfor
static int phone_table[7][7]={{-1,-1,ctcK_TpSuspended,ctcK_TpDisconnected,-1,-1,-1},
{ctcK_OpAnswered,-1,-1,ctcK_TpDisconnected,-1,ctcK_Other,-1},
{ctcK_TpRetrieved,-1,-1,-1,-1,-1,-1},
{-1,ctcK_DestSeized,-1,-1,ctcK_InboundCall,-1,-1},
{ctcK_TpAnswered,-1,-1,-1,-1,-1,-1},
{0,0,0,0,0,0,0},
{0,0,0,0,0,-1}
};
static BOOL CALLBACK DialingDlgProc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if(uMsg==WM_COMMAND)
{
if(LOWORD(wParam)==IDCANCEL)
{
while(!::PostMessage(NULL, UM_CANCELDIAL, (WPARAM)0, (LPARAM)0))
Sleep(100);
}
return(TRUE);
}
return(FALSE);
}
UINT _stdcall CDirectoryNumber::MointorThread(void* p)
{
CoInitialize(NULL);
CDirectoryNumber* pDN=(CDirectoryNumber* )p;
DWORD dwStatus=0;
if (p)
{
while (pDN->m_bMonitorOn)
{
try
{
ctcEventData* pevent=new ctcEventData;
if (pevent)
{
dwStatus=ctcGetEvent(pDN->m_channelId, pevent, 0);
if (dwStatus!=ctcSuccess)
{
char temp[200];
wsprintf(temp,"ctc getevent failed. error code: %d",dwStatus);
WriteLog(temp);
}else
{//Get a dn event, process it.
list<WPARAM> eventList;
if (!pDN->DefaultHandler(pevent,&eventList))
{//post event to pumpWindow
for (int i=1;i<eventList.size();i++)
{// post fake message, if it exsit
list<WPARAM>::iterator item=eventList.begin();
eventList.remove(*item);
ctcEventData* fakeEvent=new ctcEventData;
if (fakeEvent)
{
fakeEvent->event=*item;
while (!PostMessage(h_gPumpWnd,UM_DNEVENT,(WPARAM)pDN,(LPARAM)fakeEvent))
Sleep(100);
}else
{
break;
}
}
//Post this event
while (!PostMessage(h_gPumpWnd,UM_DNEVENT,(WPARAM)pDN,(LPARAM)pevent))
Sleep(100);
}
}
}else
{
WriteLog("Allocate buffer for ctcEventData failed.");
}
}catch(...)
{
WriteLog("ctc getevent exception failed");
}
}
}
CoUninitialize();
return 0;
}
PHONE_STATE CDirectoryNumber::GetPhoneState(UINT ctcState)
{
//enum PHONE_STATE
//{
// CTC_NULL=3, // means this state's index in this table
// CTC_INITIAL=3,
// CTC_ACTIVE=0,
// CTC_DELIVER=1,
// CTC_RECEIVE=4,
// CTC_HOLD=2,
// CTC_UNKNOWN=5,
// CTC_ERROR=6
//}
PHONE_STATE ctc;
switch (ctcState)
{
case ctcK_ActiveState:
ctc=CTC_ACTIVE;
break;
case ctcK_DeliverState:
ctc=CTC_DELIVER;
break;
case ctcK_UnavailableState:
case ctcK_FailState:
ctc=CTC_ERROR;
break;
case ctcK_HoldState:
ctc=CTC_HOLD;
break;
case ctcK_InitiateState:
case ctcK_NullState:
ctc=CTC_NULL;
break;
case ctcK_ReceiveState:
ctc=CTC_RECEIVE;
break;
case ctcK_UnknownState:
ctc=CTC_UNKNOWN;
default:
ctc=CTC_UNKNOWN;
break;
}
return ctc;
}
BOOL CDirectoryNumber::SearchRoutine(PHONE_STATE start,PHONE_STATE end,list<UINT>* eventList,int* level)
{
BOOL bRet=FALSE;
if (++(*level)<=MAX_STEP_COUNT)
{
if (phone_table[start][end]>=0)
{
//find the path
bRet=TRUE;
eventList->push_front(phone_table[start][end]);
}else
{
for (int i=0;i<=sqrt(sizeof(phone_table)/sizeof(int))-1;i++)
{
PHONE_STATE tempEnd=(PHONE_STATE)i;
if (phone_table[start][tempEnd]>=0)
{
if (SearchRoutine(tempEnd,end,eventList,level))
{
eventList->push_front(phone_table[start][tempEnd]);
bRet=TRUE;
break;
}
}
}
}
}
(*level)--;
return bRet;
}
BOOL CDirectoryNumber::ValidateStateRoutine(UINT startState,UINT endState,list<UINT>*routine)
{
PHONE_STATE phone_start=GetPhoneState(startState);
PHONE_STATE phone_end=GetPhoneState(endState);
routine->clear();
int step=0;
return SearchRoutine(phone_start,phone_end,routine,&step);
}
BOOL CDirectoryNumber::Initialize(char* dn,ctcChanId chanelID, ADDRTYPES type, CMichelleCTI *pCTI)
{
BOOL bRet=FALSE;
memset(&m_curState,0,sizeof(m_curState));
m_curState.state=ctcK_NullState;
m_hNotifyApi=CreateEvent(NULL,FALSE,TRUE,NULL); //ini as signal
m_hConfirm=CreateEvent(NULL,FALSE,FALSE,NULL); //ini as nonsingal
if (m_hNotifyApi && m_hConfirm)
{
m_ActiveCallRef=0;
m_HoldCallRef=0;
m_bInvokingApi=FALSE;
m_pCTI = pCTI;
m_channelId=chanelID;
m_type = type;
m_bMonitorOn=TRUE; // The monitor thread can execute now
int nLen=strlen(dn)>sizeof(m_ThisDN)?sizeof(m_ThisDN):strlen(dn);
memcpy(m_ThisDN,dn,nLen);
m_hMonitor=(HANDLE)_beginthreadex(NULL,0,CDirectoryNumber::MointorThread,
this, 0, &m_idMonitor);
bRet=(m_hMonitor!=NULL);
}
return bRet;
}
void CDirectoryNumber::Uninitialize()
{
if (m_hMonitor)
{
m_bMonitorOn=FALSE;
WaitForSingleObject(m_hMonitor, INFINITE);
CloseHandle(m_hMonitor);
m_hMonitor=NULL;
m_idMonitor=0;
}
if (m_hNotifyApi)
{
CloseHandle(m_hNotifyApi);
m_hNotifyApi=NULL;
}
if (m_hConfirm)
{
CloseHandle(m_hConfirm);
m_hConfirm=NULL;
}
m_HoldCallRef=0;
m_ActiveCallRef=0;
m_bInvokingApi=FALSE;
return;
}
void CDirectoryNumber::ClearApiInfo()
{
m_lErrCode=0;
m_ErrMsg="";
return;
}
BOOL CDirectoryNumber::OnDialing()
{
BOOL bRet=FALSE;
m_bInvokingApi=TRUE;
HWND hDlg = CreateDialog(h_gInstance, MAKEINTRESOURCE(IDD_DIALINGDLG), NULL, DialingDlgProc);
ATLASSERT(hDlg);
RECT rcDlg, rcDesk;
GetWindowRect(GetDesktopWindow(), &rcDesk);
GetWindowRect(hDlg, &rcDlg);
int x = ((rcDesk.right - rcDesk.left) - (rcDlg.right - rcDlg.left)) / 2 + rcDesk.left;
int y = ((rcDesk.bottom - rcDesk.top) - (rcDlg.bottom - rcDlg.top)) / 2 + rcDesk.top;
if(m_bDisableDialing)
{
SetWindowPos(hDlg, HWND_TOPMOST, -400, -400, 0, 0, SWP_NOSIZE);
}
else
{
SetWindowPos(hDlg, HWND_TOPMOST, x, y, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE);
}
UINT lastState=m_curState.state; // record the last phone state
list<PHONE_STATE> tempState; // the full state routine except the final state
tempState.clear();
tempState.push_back(CTC_NULL);
tempState.push_back(CTC_INITIAL);
tempState.push_back(CTC_DELIVER);
DWORD result=0;
while (TRUE)
{
// Process the message in this message queue
MSG msg;
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
{
if (!IsDialogMessage(hDlg,&msg))
{
if(msg.message==WM_PAINT || msg.message==WM_NCPAINT || msg.message==WM_ERASEBKGND)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}else if (!msg.hwnd && msg.message == UM_CANCELDIAL)
{
if (m_HoldCallRef!=0)
ReconnectCall();
else
ReleaseCall(NULL);
}
}
//wait for message or fired event
result=MsgWaitForMultipleObjects(1,&m_hNotifyApi,FALSE,TIME_WAIT_MESSAGE,QS_ALLEVENTS);
if (result=WAIT_TIMEOUT)
{//time out
break;
}else
{// the telephon may update to a new state
if (!InSet(m_curState.state,tempState))
{// The current state has not belonged to this api's state routine
break;
}else
{// update the current state as the last state
lastState=m_curState.state;
//notify the defaulthandler that this api has check the current state
SetEvent(m_hConfirm);
}
}
}//end while (true)
if (result==WAIT_TIMEOUT)
{
m_lErrCode=CTC_TIMEOUT_ERR;
m_ErrMsg="This api invoke is time out";
}else
{
list<UINT> routine;
if (ValidateStateRoutine(lastState,m_curState.state,&routine))
{//ok,quit
bRet=TRUE;
}else
{//This state transmission is invailed
m_lErrCode=CTC_RELEASECALL_ERR;
m_ErrMsg="Release call reached an invaild state";
}
}
SetEvent(m_hConfirm);
m_bInvokingApi=TRUE;
return bRet;
}
BOOL CDirectoryNumber::GetAnsiFromBSTR(char** dest, BSTR source)
{
BOOL ret=TRUE;
int nLength=WideCharToMultiByte(CP_ACP,0,source,-1,NULL,0,NULL,NULL);
if (nLength>0)
{
char* pTemp=new char[nLength];
if (pTemp)
{
if (WideCharToMultiByte(CP_ACP,0,source,-1,pTemp,nLength,NULL,NULL))
{
*dest=new char[nLength*2];
int nDestLen=0;
if (*dest)
{
for (UINT i=0;i<strlen(pTemp);i++)
{
if (pTemp[i]=='/')
{
(*dest)[nDestLen]='/';
nDestLen++;
}
(*dest)[nDestLen]=pTemp[i];
nDestLen++;
}
(*dest)[nDestLen]='\0';
}else
{
ret=FALSE;
}
}else
ret=FALSE;
delete pTemp;
pTemp=NULL;
}else
ret=FALSE;
}
return ret;
}
BOOL CDirectoryNumber::GetAnsiFromInt(char** dest, int source)
{
BOOL ret=TRUE;
*dest=new char[sizeof(int)];
if (*dest) _itoa(source,*dest,16);
else ret=FALSE;
return ret;
}
BOOL CDirectoryNumber::KVListToAppString(IKVList* pkvlist, char* pAppString,UINT bufLen)
{
//Transform character: "/"
// /k: type : key
// /s: type: string
// /i: type: int
// /b: type: binary
// /l: type: binary length (/l23/l)
//sample: /kRick/sMyname/kName/i100
BOOL bReturn=TRUE;
if (pkvlist)
{
KVRESULTS res=pkvlist->InitScanLoop();
if (KVR_Successful==res)
{
IKVPair* pkvpair=NULL;
while (pkvpair=pkvlist->NextPair())
{
pkvpair->AddRef();
BSTR key=NULL;
char* pKey=NULL;
if (SUCCEEDED(pkvpair->get_Key(&key)))
{
if (GetAnsiFromBSTR(&pKey,key))
{
// ValidateString(pKey,bufLen);
if (strlen(pKey)+strlen(pAppString)+3<=bufLen)
{
strcat(pAppString,"/k");
strcat(pAppString,pKey);
key=NULL;
if (pKey)
{
delete pKey;
pKey=NULL;
}
KVTYPES type;
if (SUCCEEDED(pkvpair->get_Type(&type)))
{
int nVal=0;
switch (type)
{
case KVT_String:
pkvpair->get_StringValue(&key);
if (GetAnsiFromBSTR(&pKey,key))
{
// ValidateString(pKey,bufLen);
if (strlen(pKey)+strlen(pAppString)+3<=bufLen)
{
strcat(pAppString,"/s");
strcat(pAppString,pKey);
}else
bReturn = FALSE;
}else
{
bReturn = FALSE;
}
if (pKey)
{
delete pKey;
pKey=NULL;
}
key=NULL;
break;
case KVT_Int:
pkvpair->get_IntValue(&nVal);
if (GetAnsiFromInt(&pKey,nVal))
{
if (strlen(pKey)+strlen(pAppString)+3<=bufLen)
{
strcat(pAppString,"/i");
strcat(pAppString,pKey);
}else
bReturn= FALSE;
}else
bReturn= FALSE;
if (pKey)
{
delete pKey;
pKey=NULL;
}
break;
default:
bReturn=FALSE;
}
}else//pkvpair->Type
{
bReturn =FALSE;
}
}else//LENGTH CHECK
{
bReturn =FALSE;
}
}else//GetAnsiFromBSTR
{
bReturn =FALSE;
}
if (pKey)
{
delete pKey;
pKey=NULL;
}
key=NULL;
}else//pkvpair->Key
{
bReturn = FALSE;
}
pkvpair->Release();
pkvpair=NULL;
}//while
}else//KVR_Successful==res
{
bReturn= FALSE;
}
}//if (pkvlist)
else
{
bReturn =TRUE;
}
if (!bReturn )
ZeroMemory(pAppString, strlen(pAppString));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -