www.pudn.com > lucent_softphone.rar > MichelleCTI.cpp
// MichelleCTI.cpp : Implementation of CMichelleCTI #include "stdafx.h" #include "LucentCti.h" #include "KVPair.h" #include "KVList.h" #include "CTIEvent.h" #include "MichelleCTI.h" #include#define szLogPath "c:\\LUCENTLOG" // the log file path #define EVENT_BUF_LEN 800 // the lucent event bufer default length /////////////////////////////////////////////////////////////////////////////// //Area for global functions HINSTANCE CMichelleCTI::m_hInstance=NULL; HWND CMichelleCTI::m_hSynWnd=NULL; HANDLE CMichelleCTI::m_hPumpTrd=NULL; UINT CMichelleCTI::m_dwPumpId=0; DECLARE_CASTER(CDirectoryNumber, IDirectoryNumber) DECLARE_CREATOR(CCTIEvent, ICTIEvent) DECLARE_CREATOR(CDirectoryNumber, IDirectoryNumber) //write log void WriteLog(char* pData) { #ifdef _WRITELOG time_t now; time(&now); tm nowTime=*localtime(&now); char logfile[1024]={0}; sprintf(logfile,"%s\\LucentCTILog%02d_%02d_%04d.log",szLogPath,nowTime.tm_mon+1,nowTime.tm_mday,nowTime.tm_year+1900); HANDLE hLogFile=CreateFile(logfile,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); if (hLogFile==INVALID_HANDLE_VALUE) { if (!CreateDirectory(szLogPath,NULL)) return; else hLogFile=CreateFile(logfile,GENERIC_WRITE|GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); } if (hLogFile!=INVALID_HANDLE_VALUE) { SetFilePointer(hLogFile,NULL,NULL,FILE_END); sprintf(logfile,"%2d:%2d:%2d Message:%s\r\n",nowTime.tm_hour,nowTime.tm_min,nowTime.tm_sec,pData); DWORD dw; WriteFile(hLogFile,logfile,strlen(logfile),&dw,NULL); CloseHandle(hLogFile); } #endif } // the pump thread, all lucent api must post message to me at first, then // I'll send this message to the synchronic window DWORD PumpThread (HWND hSynWnd) { CoInitialize(NULL); MSG msg; while (GetMessage(&msg,NULL,0,0)) { if (IsWindow(hSynWnd)) if (!SendMessage(hSynWnd,msg.message,msg.wParam,msg.lParam)) Sleep(100); } CoUninitialize(); return 0; } //the registried lucent stream monitor function.Get all message here //void WINAPI monitorStream(CMichelleCTI* pCti) void WINAPI monitorStream(unsigned long p) { // the stream event process event CMichelleCTI* pCti=(CMichelleCTI*)p; //PostThreadMessage regulation: //msg: um_cti or um_dn_csta or um_dn_att or um_apifailed //wParam: cti class or dn class //lParam: evnet pointer if (pCti) { byte* eventBuf=new byte[EVENT_BUF_LEN]; if (eventBuf==NULL) return; unsigned short nEventBufLen=EVENT_BUF_LEN; ATTPrivateData_t* data=new ATTPrivateData_t; // the private data if (data) { data->length=ATT_MAX_PRIVATE_DATA; CSTAEvent_t* cstaEvent=NULL; // the csta event ATTEvent_t* attEvent=NULL; // the att event unsigned short nNumEvent=0; // the event queue 's member account RetCode_t ret=acsGetEventPoll(pCti->m_serverHandle,eventBuf,&nEventBufLen, (PrivateData_t*)data,&nNumEvent); if (ret!=0) { if (ACSERR_NOMESSAGE==ret) {//There is no message,ok return; }else if (ACSERR_UBUFSMALL==ret) {//The buffer is too small delete eventBuf; eventBuf=new byte[ nEventBufLen]; if (!eventBuf) { PostThreadMessage(pCti->m_dwPumpId,UM_APIFAILED,(WPARAM)pCti,0); WriteLog("event buffer too small, realloc failed."); } //try to get the event again ret=acsGetEventPoll(pCti->m_serverHandle,eventBuf,&nEventBufLen, (PrivateData_t*)data,&nNumEvent); if (ret!=0) { PostThreadMessage(pCti->m_dwPumpId,UM_APIFAILED,(WPARAM)pCti,0); WriteLog("get event twince, but all failed."); } }else { PostThreadMessage(pCti->m_dwPumpId,UM_APIFAILED,(WPARAM)pCti,0); WriteLog("get event failed."); } }else {// ok, we get a csta event cstaEvent=(CSTAEvent_t*)eventBuf; } if (cstaEvent) { dnevent* pEvent=NULL; //now process the csta event switch(cstaEvent->eventHeader.eventClass) { case ACSCONFIRMATION: // the acs api confirmation switch (cstaEvent->eventHeader.eventType) { case ACS_OPEN_STREAM_CONF: case ACS_CLOSE_STREAM_CONF: //acs ok PostThreadMessage(pCti->m_dwPumpId,UM_CTI,(WPARAM)pCti,cstaEvent->eventHeader.eventType); break; case ACS_UNIVERSAL_FAILURE_CONF: //failure confirm if (pCti->m_iDn) {// This message must be post to dn if the dn has been registered pEvent=new dnevent(cstaEvent,NULL); if (pEvent) { PostThreadMessage(pCti->m_dwPumpId,UM_DN,(WPARAM)pCti->m_iDn,(LPARAM)pEvent); eventBuf=NULL; cstaEvent=NULL; } }else { pCti->m_lErrCode=cstaEvent->event.cstaConfirmation.u.universalFailure.error; pCti->m_errType=ET_LUCENT_CONF; PostThreadMessage(pCti->m_dwPumpId,UM_CTI,(WPARAM)pCti,UM_APIFAILED); char pTemp[100]={0}; wsprintf(pTemp,"ACS_UNIVERSAL_FAILURE_CONF error code:%d(cti)",pCti->m_lErrCode); WriteLog(pTemp); } break; default: //PostThreadMessage(pCti->m_dwPumpId,UM_CTI,(WPARAM)pCti,UM_APIFAILED); WriteLog("Get an unknown ascconfirmation event."); break; } break; case ACSUNSOLICITED: if (pCti->m_iDn) {// This message must be post to dn if the dn has been registered pEvent=new dnevent(cstaEvent,NULL); if (pEvent) { PostThreadMessage(pCti->m_dwPumpId,UM_DN,(WPARAM)pCti->m_iDn,(LPARAM)pEvent); eventBuf=NULL; cstaEvent=NULL; } }else {//send to cti object pCti->m_lErrCode=cstaEvent->event.acsUnsolicited.u.failureEvent.error; pCti->m_errType=ET_LUCENT_CONF; pCti->m_ErrMsg="Get an acsunsolicited event."; PostThreadMessage(pCti->m_dwPumpId,UM_CTI,(WPARAM)pCti,UM_APIFAILED); char pTemp[100]={0}; wsprintf(pTemp,"ACSUNSOLICITED error code:%d(cti)",pCti->m_lErrCode); WriteLog(pTemp); } break; case CSTACONFIRMATION: //the csta api confirmation pEvent=new dnevent(cstaEvent,NULL); if (pEvent) { PostThreadMessage(pCti->m_dwPumpId,UM_DN,(WPARAM)pCti->m_iDn,(LPARAM)pEvent); eventBuf=NULL; cstaEvent=NULL; } break; case CSTAUNSOLICITED: //post the csta message switch (cstaEvent->eventHeader.eventType) { case CSTA_DELIVERED: //post the att event if (data->length>0) {//contains private data,send ATTEvent attEvent=new ATTEvent_t; //this buffer will be processed and deleted in future if (attEvent) { ret=attPrivateData(data,attEvent); if (ret!=0) { delete attEvent; attEvent=NULL; } } } break; default: break; } pEvent=new dnevent(cstaEvent,attEvent); if (pEvent) { PostThreadMessage(pCti->m_dwPumpId,UM_DN,(WPARAM)pCti->m_iDn,(LPARAM)pEvent); eventBuf=NULL; cstaEvent=NULL; }else { delete attEvent; attEvent=NULL; } eventBuf=NULL; cstaEvent=NULL; break; }//switch(cstaEvent->eventHeader.eventClass) } // before exit, clear buffer if (eventBuf) { delete eventBuf; eventBuf=NULL; cstaEvent=NULL; } //call fun again to process event if (nNumEvent>1) monitorStream((unsigned long)pCti); } } return; } // the synchronic window message process function. All message will be processed here LRESULT CALLBACK SynchronicWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {// the synchronic window message dispatcher CCTIEvent *pCEvent; ICTIEvent *pIEvent; CMichelleCTI* pCti=NULL; CDirectoryNumber* pDn=NULL; CSTAEvent_t* cstaEvent=NULL; dnevent* pEvent=NULL; switch(msg) { case UM_APIFAILED: if (wParam!=0) { pCti=(CMichelleCTI*)wParam; if(SUCCEEDED(CreateClass(&pCEvent, &pIEvent))) { pCEvent->m_GenesysEvent=EVT_Error; pCti->Fire_Event(pIEvent); pIEvent->Release(); } else { pCti->Fire_Event(NULL); } } break; case UM_CTI: if (wParam!=0) { pCti=(CMichelleCTI*)wParam; if (!pCti->DefaultHandler(lParam))//event name { if(SUCCEEDED(CreateClass(&pCEvent, &pIEvent))) { switch(lParam) { case UM_APIFAILED: pCEvent->m_GenesysEvent=EVT_Error; break; case ACS_OPEN_STREAM_CONF: pCEvent->m_GenesysEvent=EVT_LinkConnected; break; /////////////MARK by rick --begin // case ACS_CLOSE_STREAM_CONF: // pCEvent->m_GenesysEvent=EVT_LinkDisconnected; // break; /////////////MARK --end } pCti->Fire_Event(pIEvent); pIEvent->Release(); } else { pCti->Fire_Event(NULL); } } } break; case UM_DN: if (wParam!=0) { pDn = I2C((IDirectoryNumber*)wParam); pEvent=(dnevent*) lParam; if (!pDn->DefaultHandler(pEvent)) { if(SUCCEEDED(CreateClass(&pCEvent, &pIEvent))) { pCEvent->SetEvent(pEvent); pDn->Fire_Event(pIEvent); pIEvent->Release(); } else { pCti->Fire_Event(NULL); } delete pEvent; } lParam=0; // the dnevent has been deleted } if (wParam==0 && lParam!=0) delete ((dnevent*) lParam); break; default: return(DefWindowProc(hwnd, msg, wParam, lParam)); } return (0l); } BOOL GlobalStartup(HINSTANCE hInstance) { BOOL ret=FALSE; if (hInstance) { CMichelleCTI::m_hInstance=hInstance; //Create the message synchronic window WNDCLASS wc; wc.style = 0; wc.lpfnWndProc = SynchronicWndProc; wc.cbClsExtra = wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = _T("LUCENT_CTI_SYN_WND"); CMichelleCTI::m_hSynWnd=NULL; if(RegisterClass(&wc)) CMichelleCTI::m_hSynWnd = CreateWindow(wc.lpszClassName, NULL, WS_DISABLED, 0, 0, 0, 0, NULL, NULL, hInstance, NULL); if (CMichelleCTI::m_hSynWnd) { CMichelleCTI::m_hPumpTrd=(HANDLE)_beginthreadex(NULL,0,(ALT_LPTHREAD_START_ROUTINE)PumpThread, CMichelleCTI::m_hSynWnd,0, &CMichelleCTI::m_dwPumpId); if (CMichelleCTI::m_hPumpTrd) ret=TRUE; } } return ret; } void GlobalCleanup() { if (CMichelleCTI::m_hSynWnd) { DestroyWindow(CMichelleCTI::m_hSynWnd); CMichelleCTI::m_hSynWnd=NULL; } if (CMichelleCTI::m_hPumpTrd && CMichelleCTI::m_dwPumpId) { PostThreadMessage(CMichelleCTI::m_dwPumpId,WM_QUIT,0,0); while (WaitForSingleObject(CMichelleCTI::m_hPumpTrd,100)==WAIT_TIMEOUT) { MSG msg; if (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } CloseHandle(CMichelleCTI::m_hPumpTrd ); } return; } // change the bstring to ansi string BOOL B2C(BSTR bStr,char* pBuf,int nBufLen) { BOOL ret=FALSE; if (pBuf && nBufLen>0) { if (bStr) { int nLen=WideCharToMultiByte(CP_ACP,0,bStr,-1,NULL,0,NULL,NULL); if (nLen<=nBufLen) { if (WideCharToMultiByte(CP_ACP,0,bStr,-1,pBuf,nBufLen,NULL,NULL)>0) ret=TRUE; } }else {// the BSTR is a null string memset(pBuf,0,nBufLen); ret=TRUE; } } return ret; } ///////////////////////////////////////////////////////////////////////////// // CMichelleCTI BOOL CMichelleCTI::DefaultHandler(long cstaEvent) { BOOL notFire=TRUE; switch (cstaEvent) { case UM_APIFAILED: case ACS_OPEN_STREAM_CONF: case ACS_CLOSE_STREAM_CONF: notFire=FALSE; break; } while (!PostMessage(NULL,UM_CMDMSG,cstaEvent,0)) Sleep(100); if (!notFire) ReplyMessage(0l); return notFire; } STDMETHODIMP CMichelleCTI::get_Initialized(BOOL *pVal) { // TODO: Add your implementation code here *pVal=m_serverHandle!=0; return S_OK; } STDMETHODIMP_(BOOL) CMichelleCTI::Initialize(PBXTYPES pbxtype, BSTR server, int port, BSTR name, BSTR pass) { // TODO: Add your implementation code here BOOL bRet=FALSE; if (B2C(server,m_serverId,sizeof(m_serverId)) && B2C(name,m_loginId,sizeof (m_loginId)) && B2C(pass,m_pwdId,sizeof (m_pwdId))) { AppName_t appName={0}; strcpy(appName,"Lucent cti dll"); Version_t version={0}; strcpy(version,"TS1-2"); InvokeIDType_t invokeType=APP_GEN_ID; StreamType_t streamType=ST_CSTA; Level_t level=ACS_LEVEL1; //This param is ignored // set the private data version ATTPrivateData_t OpenData; strcpy(OpenData.vendor,"VERSION"); // strcpy(&OpenData.data[1],"AT&T Definity G3#6"); OpenData.data[0]=PRIVATE_DATA_ENCODING; attMakeVersionString("6",&OpenData.data[1]); OpenData.length=strlen(&OpenData.data[1])+2; //error prepaired m_lErrCode=0; m_errType=ET_NOERROR; RetCode_t ret; char pTemp[300]; wsprintf(pTemp,"acsOpenStream: user:%s,pwd:%s",m_loginId,m_pwdId); WriteLog(pTemp); try { ret=acsOpenStream(&m_serverHandle,invokeType,m_invokeId,streamType, &m_serverId,&m_loginId,&m_pwdId,&appName,level,&version, 5,//send queue size 5,//additional packet buffer 20,//receive queue size 5,//additional packet buffer (PrivateData_t*)&OpenData/*private data*/); }catch(...) { ret=LUCENT_UNKNOWN; m_errType=ET_LUCENT; m_ErrMsg="acsOpenStream failed by unknown error."; } if (ret<0) {//ERROR m_errType=ET_LUCENT; m_lErrCode=ret; m_ErrMsg="acsOpenStream return failed."; }else {//OK m_lErrCode=ERR_INI; //Regist the message process function ret=acsSetESR(m_serverHandle,monitorStream,(unsigned long)this,TRUE); if (ret>=0) { BOOL bQuit=FALSE; //waiting for the acs confirmation's arrival MSG msg; while (GetMessage(&msg,NULL,0,0)) { if (msg.message==UM_CMDMSG && msg.hwnd==NULL) { switch(msg.wParam) { case ACS_OPEN_STREAM_CONF: bRet=TRUE; bQuit=TRUE; break; case UM_APIFAILED: if (m_lErrCode==ERR_INI) { m_errType=ET_LUCENT; m_lErrCode=LUCENT_UNKNOWN; m_ErrMsg="acsSetESR failed."; } bQuit=TRUE; break; default: break; } if (bQuit) break; } } }else { m_errType=ET_LUCENT; m_lErrCode=ret; } } }else { m_errType=ET_USER; m_lErrCode=LUCENT_INVALID_PARAM; m_ErrMsg="Specified an error parameter."; } if (!bRet) { char tep[300]={0}; wsprintf((char*)&tep,"error:%s,code:%d.",m_ErrMsg.c_str(),m_lErrCode); WriteLog((char*)&tep); } return bRet; } STDMETHODIMP_(void) CMichelleCTI::Uninitialize() { // TODO: Add your implementation code here //IF {m_iDn} do BOOL bRet=FALSE; if (m_iDn) UnregisterDN(NULL); // acsAbortStream(m_serverHandle,NULL); WriteLog("acsCloseStream service."); m_lErrCode=ERR_INI; RetCode_t ret=acsCloseStream(m_serverHandle,m_invokeId,NULL); if (ret==ACSPOSITIVE_ACK) { MSG msg; while (GetMessage(&msg,NULL,0,0)) { if (msg.message==UM_CMDMSG) { if (msg.wParam==UM_APIFAILED) { if (m_lErrCode!=ERR_INI) { m_errType=ET_LUCENT; m_lErrCode=LUCENT_UNKNOWN; m_ErrMsg="acsCloseStream unknown error."; } break; }else if (msg.wParam==ACS_CLOSE_STREAM_CONF) { bRet=TRUE; break; } } } }else { m_errType=ET_LUCENT; m_lErrCode=ret; m_ErrMsg="acsCloseStream return error."; } if (!bRet) { char tep[300]={0}; wsprintf((char*)&tep,"error:%s,code:%d.",m_ErrMsg.c_str(),m_lErrCode); WriteLog((char*)&tep); } return; } STDMETHODIMP_(IDirectoryNumber*) CMichelleCTI::RegisterDN(BSTR dn, ADDRTYPES type, BSTR acdpos) { if (type==AT_DN || type==AT_Unknown) { CDirectoryNumber *pExtDN = NULL; IDirectoryNumber *iExtDN = NULL; HRESULT hRes = CreateClass(&pExtDN, &iExtDN); if(SUCCEEDED(hRes)) { m_iDn=iExtDN; m_iDn->AddRef(); if (!pExtDN->Initialize(dn,m_serverHandle,m_invokeId+1)) { m_iDn->Release(); m_iDn=NULL; m_errType=ET_USER; m_lErrCode=LUCNET_DNINI_ERR; } // iExtDN->Release(); iExtDN=NULL; }else { m_errType=ET_COM; m_lErrCode=hRes; m_ErrMsg="Create a com instance failed."; } }else { m_errType=ET_USER; m_lErrCode=LUCENT_ADDRESSTYPE_ERR; m_ErrMsg="Sepcified an error parameter."; } if (m_iDn==NULL) { char tep[300]={0}; wsprintf((char*)tep,"error:%s,code:%d",m_ErrMsg.c_str(),m_lErrCode); } return m_iDn; } STDMETHODIMP_(void) CMichelleCTI::UnregisterDN(LPDN dn) { // TODO: Add your implementation code here if (m_iDn) { CDirectoryNumber* pExtDn=I2C(m_iDn); pExtDn->Uninitialize(); // long n=m_iDn->AddRef(); m_iDn->Release(); m_iDn=NULL; } } STDMETHODIMP CMichelleCTI::get_ErrType(ERRORTYPES *pVal) { // TODO: Add your implementation code here *pVal=m_errType; return S_OK; } STDMETHODIMP CMichelleCTI::get_ErrCode(long *pVal) { // TODO: Add your implementation code here *pVal=m_lErrCode; return S_OK; } STDMETHODIMP CMichelleCTI::get_ErrMsg(BSTR *pVal) { // TODO: Add your implementation code here *pVal=C2B(m_ErrMsg.c_str()); return S_OK; } STDMETHODIMP_(BOOL) CMichelleCTI::Init(BSTR server, int port) { ATLASSERT(FALSE); return TRUE; } STDMETHODIMP_(void) CMichelleCTI::Login(BSTR AgentID) { ATLASSERT(FALSE); return ; } STDMETHODIMP_(void) CMichelleCTI::ReportConfirm(BOOL confirm) { ATLASSERT(FALSE); return ; } STDMETHODIMP_(void) CMichelleCTI::ReportResult(BSTR ReqID, BOOL result, BSTR reason) { ATLASSERT(FALSE); return ; } STDMETHODIMP_(void) CMichelleCTI::ReportStatus(BSTR AgentID, AGENTSTATES AgentState) { ATLASSERT(FALSE); return ; } STDMETHODIMP_(void) CMichelleCTI::Uninit() { ATLASSERT(FALSE); return ; }