⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dominohandler.cpp

📁 基于domino系统邮件数据库编写的邮件助手程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// DominoHandler.cpp: implementation of the CDominoHandler class.
//////////////////////////////////////////////////////////////////////
/*
TODO: 
如果服务器两项配置如下,可能会导致请求服务配置时输出UTF8的XML文档,而服务代理里输出的为GB2312,从而导致“没有可用服务”错误。
		1、“Domino Web引擎”中“语言”-“缺省字符串资源语言”配置为“中文(简体)”
		2、“Domino Web引擎”中“字符集”-“使用 UTF-8 输出”配置为“是”
测试-使用某用户通过IE登录系统后,直接访问地址:
	http://xxxx/doDominoMinder.nsf/MinderService?OpenAgent&ver=2.002&Action=getservicecfg
*/

#include "stdafx.h"
#include "DominoMinder.h"
#include "DominoHandler.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// CDInternetSession
//////////////////////////////////////////////////////////////////////

CDInternetSession::CDInternetSession(LPCTSTR pszAppName, int nMethod)
	: CInternetSession(pszAppName, 1, nMethod)
{
	this->SetOption( INTERNET_OPTION_CONNECT_TIMEOUT, 1000*30 );	//好像无效:(
	this->SetOption( INTERNET_OPTION_CONNECT_BACKOFF, 1000 );
	this->SetOption( INTERNET_OPTION_CONNECT_RETRIES, 2 );
	this->EnableStatusCallback(TRUE);
}
void CDInternetSession::OnStatusCallback(
	DWORD dwContext,	// 1
	DWORD dwInternetStatus,
	LPVOID lpvStatusInformation,
	DWORD dwStatusInformationLen )
{
	//if (!bProgressMode) return;
	//TODO: 两次 INTERNET_STATUS_HANDLE_CREATED?

	char szStatus[128]; memset(szStatus,0,sizeof(szStatus));
	switch ( dwInternetStatus )
	{
	case INTERNET_STATUS_RESOLVING_NAME:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_RESOLVING_NAME | %s\0", lpvStatusInformation );
		break;
	case INTERNET_STATUS_NAME_RESOLVED:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_NAME_RESOLVED | %s\0", lpvStatusInformation );
		break;
	case INTERNET_STATUS_CONNECTING_TO_SERVER:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_CONNECTING_TO_SERVER | %s\0", lpvStatusInformation );
		break;
	case INTERNET_STATUS_CONNECTED_TO_SERVER:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_CONNECTED_TO_SERVER | %s\0", lpvStatusInformation );
		break;
	case INTERNET_STATUS_SENDING_REQUEST:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_CONNECTED_TO_SERVER\0" );
		break;
	case INTERNET_STATUS_REQUEST_SENT:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_REQUEST_SENT\0" );
		break;
	case INTERNET_STATUS_RECEIVING_RESPONSE:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_RECEIVING_RESPONSE\0" );
		break;
	case INTERNET_STATUS_RESPONSE_RECEIVED:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_RESPONSE_RECEIVED\0" );
		break;
	case INTERNET_STATUS_CLOSING_CONNECTION:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_CLOSING_CONNECTION\0" );
		break;
	case INTERNET_STATUS_CONNECTION_CLOSED:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_CONNECTION_CLOSED\0" );
		break;
	case INTERNET_STATUS_HANDLE_CREATED:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_HANDLE_CREATED\0" );
		break;
	case INTERNET_STATUS_HANDLE_CLOSING:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_HANDLE_CLOSING\0" );
		break;
	case INTERNET_STATUS_COOKIE_SENT:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_COOKIE_SENT\0" );
		break;
	case INTERNET_STATUS_COOKIE_RECEIVED:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_COOKIE_RECEIVED\0" );
		break;
	case INTERNET_STATUS_REDIRECT:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_REDIRECT | %s\0", lpvStatusInformation );
		break;
	case INTERNET_STATUS_COOKIE_HISTORY:
		sprintf( szStatus, "InternetStatus = INTERNET_STATUS_COOKIE_HISTORY\0" );
		break;
	default:
		sprintf( szStatus, "InternetStatus = %d\0", dwInternetStatus );
	}

#ifdef _DEBUG
	if ( (dwInternetStatus==INTERNET_STATUS_REDIRECT) && (strlen(szStatus) > 0) ) {
		CLog::WriteLine( szStatus );
	}
#endif
}

/////////////////////////////////////////////////////////////////////
//	CHttpRequestThread
/////////////////////////////////////////////////////////////////////

IMPLEMENT_DYNCREATE(CHttpRequestThread, CWinThread);

CHttpRequestThread::~CHttpRequestThread()
{
	//MessageBox(NULL, "CHttpRequestThread::~CHttpRequestThread", "", MB_OK);
	m_pParm->out_bEnd = true;
}
//设置请求参数
void CHttpRequestThread::SetParm( HTTP_REQ_THREAD_PARM* pParm ){
	//MessageBox(NULL, "CHttpRequestThread::SetParm", "", MB_OK);
	m_pParm = pParm;
	m_pParm->out_bEnd = false;
	m_pParm->out_sRet = "";
	m_pParm->out_nRet = 0;
	m_pParm->out_bErr = false;
}
//发送请求
void CHttpRequestThread::sendRequest()
{
	//MessageBox(NULL, "CHttpRequestThread::sendRequest", "", MB_OK);
	CHttpFile* pHttpFile = NULL;
	//连接服务器并发送请求
	try {
		if ( m_pParm->nHttpVerb == CHttpConnection::HTTP_VERB_POST ) {
			pHttpFile = m_pParm->pHttpConnection->OpenRequest( m_pParm->nHttpVerb, m_pParm->sUrl );
			pHttpFile->SendRequestEx( m_pParm->sPostData.GetLength() );
			pHttpFile->WriteString( m_pParm->sPostData );
			pHttpFile->EndRequest();
			//CString strHeaders  = "Content-Type: application/x-www-form-urlencoded";
			//CString strHeaders = ""; //"Accept-Charset: GB2312";
			//pHttpFile->SendRequest( strHeaders, (LPVOID)(LPCTSTR)(m_pParm->sPostData), sizeof(m_pParm->sPostData) );
		} else {
			pHttpFile = m_pParm->pHttpConnection->OpenRequest( m_pParm->nHttpVerb, m_pParm->sUrl );
			pHttpFile->SendRequest();
		}
	} catch ( ... ) {
		//MessageBox(NULL, "send request err", "", MB_OK );
	}
	//获得服务器返回代码
	DWORD dwRet;
	pHttpFile->QueryInfoStatusCode( dwRet );
	m_pParm->out_nRet = dwRet;
	//获得服务器返回内容
	if ( dwRet == HTTP_STATUS_OK ) {
		CString strData;
		CString strDataFull = "";
		while ( pHttpFile->ReadString(strData) ) {
			 strDataFull += strData;
		}
		//解析返回结果
		IXMLDOMDocument *pXMLDoc;
		VARIANT_BOOL bResult;
		if(SUCCEEDED(CoInitialize(NULL)) && SUCCEEDED(CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_IXMLDOMDocument, (void**)&pXMLDoc))) {
			if(FAILED(pXMLDoc->loadXML( (_bstr_t)strDataFull, &bResult))) {
				m_pParm->out_bErr = true;
				m_pParm->out_sRet = "";
			} else {
				IXMLDOMElement* base;
				pXMLDoc->get_documentElement(&base);
				if ( base == NULL ) {
					m_pParm->out_bErr = true;
					m_pParm->out_sRet = "";
				} else {
					//如果有错误则解析错误
					wchar_t* szName;
					base->get_baseName( &szName );
					if ( _bstr_t(szName) == _bstr_t("error") ) {
						BSTR szErrMsg = NULL;
						base->get_text(&szErrMsg);	//DONE: 解码错误,中文都是“??” - servlet
						m_pParm->out_sRet = szErrMsg;
						m_pParm->out_bErr = true;
					}
					//否则返回Servlet返回的XML字符串
					else {
						m_pParm->out_sRet = strDataFull;
						m_pParm->out_bErr = false;
					}
					//
					base->Release();
				}
				//
				pXMLDoc->Release();
			}
		}
	} else {
		m_pParm->out_bErr = true;
		pHttpFile->QueryInfo( HTTP_QUERY_STATUS_TEXT, m_pParm->out_sRet );
		//DONE: 如何获得Servlet使用sendError返回的内容? - 没办法!!
	}
	pHttpFile->Close();

#ifdef _DEBUG
		CLog::WriteLine( dwRet, "HTTP_STATUS" );
		CLog::WriteLine( m_pParm->out_sRet );
#else
	if ( m_pParm->out_bErr && m_pParm->out_sRet!="" ) {
		CLog::WriteLine( dwRet, "HTTP_STATUS" );
		CLog::WriteLine( m_pParm->out_sRet );
		CLog::WriteLine( "err" );
	}
#endif
}

//发送请求
BOOL CHttpRequestThread::InitInstance() {
	//MessageBox(NULL, "CHttpRequestThread::InitInstance", "", MB_OK);
	sendRequest();
	//avoid entering standard message loop by returning FALSE
	return FALSE;
}

//////////////////////////////////////////////////////////////////////
// CDominoHandler
//////////////////////////////////////////////////////////////////////

CDominoHandler::CDominoHandler(CString strVersion, CString strServerName, CString strUserName, CString strPassword )
{
	//设置服务器名和端口
	int nIdx = strServerName.Find(":");
	if (  nIdx == -1 ) {
		m_strServerName = strServerName;
		m_nPort = INTERNET_DEFAULT_HTTP_PORT;
	} else {
		m_strServerName = strServerName.Left( nIdx );
		m_nPort = atoi( strServerName.Right( strServerName.GetLength() - nIdx -1 ) );
	}

	//初始化用户登陆名和密码
	m_strUserName = strUserName;
	m_strPassword = strPassword;

	//初始化InternetSession
	m_pInetSession = new CDInternetSession( NULL, 0 );

	//初始化HttpConnection - try https
	DWORD dwHttpRequestFlags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE
							 | INTERNET_FLAG_NO_AUTO_REDIRECT | INTERNET_FLAG_SECURE; // INTERNET_FLAG_EXISTING_CONNECT | 
	//m_pHttpConnection = m_pInetSession->GetHttpConnection( m_strServerName, dwHttpRequestFlags, m_nPort );
	m_oReqParm.pHttpConnection = m_pInetSession->GetHttpConnection( m_strServerName, dwHttpRequestFlags, m_nPort );

	//其它初始化
	m_strServiceCfg = "";
	m_nServiceCnt = -1;
	this->ResetRequest();

	//Domino服务器端Servlet的Class路径名 或 代理名
#ifdef DOMINO_SERVICE_AGENT
		m_strDominoServicePath  = DOMINO_AGENT_PATH + "&ver=" + strVersion;
#else
		m_strDominoServicePath  = DOMINO_SERVLET_PATH + "?ver=" + strVersion;
#endif
}

CDominoHandler::~CDominoHandler()
{
	Logout();
	m_pInetSession->Close();
	m_pInetSession = NULL;
	m_oReqParm.pHttpConnection = NULL;
}

//判断请求是否已完成
bool CDominoHandler::IsRequestFinished()
{
	return m_oReqParm.out_bEnd;
}

//判断请求是否成功(有数据)
//TODO: 如果登录页面也是xml的呢? -- 暂不考虑
bool CDominoHandler::IsRequestSuccessed()
{
	if ( m_oReqParm.out_bErr ) return false;
	return true;
	/*
	if ( m_oReqParm.out_nRet == HTTP_STATUS_OK ) {
		CString sRes = GetRequestResult();
		if ( sRes.Find("<?xml", 0) == 0 ) {
			return true;
		}
	}
	return false;
	*/
}
//发送请求失败的话(!IsRequestSuccessed),
//再判断是否是因为连接已超时==返回值为XML
bool CDominoHandler::IsSessionTimeout()
{
	if ( m_oReqParm.out_bErr && m_oReqParm.out_nRet==HTTP_STATUS_OK && m_oReqParm.out_sRet=="" ) {
		return true;
	} else {
		return false;
	}
	/*
	CString sRes = GetRequestResult();
	if ( sRes.Find("<?xml", 0) != 0 ) {
		return false;
	}
	return true;
	*/
}
//返回请求的返回值
CString CDominoHandler::GetRequestResult()
{
	return m_oReqParm.out_sRet;
}

//获得服务器名
CString CDominoHandler::GetServerName()
{
	CString sRet;
	sRet.Format( "%s:%d", m_strServerName, m_nPort );
	return sRet;
}

//从服务器取服务配置
//若bForceLogin==true,则失败的话不再重试
CString CDominoHandler::GetServiceCfg(bool bForceLogin)
{
#ifdef _DEBUG
	if ( m_strServiceCfg == "" ) {
		CLog::WriteLine( "请求服务配置:" + m_oReqParm.sUrl + ";服务器:"+ this->m_strServerName);
	}
#endif

	if ( m_strServiceCfg != "" ) {
		return m_strServiceCfg;
	} else {
		m_oReqParm.nHttpVerb = CHttpConnection::HTTP_VERB_GET;
		m_oReqParm.sPostData = "";
		m_oReqParm.sUrl  = m_strDominoServicePath + "&Action=getservicecfg";
		sendRequest( true );

		if ( IsRequestSuccessed() ) {
			m_strServiceCfg = GetRequestResult();
			m_nServiceCnt   = parseService();
			return m_strServiceCfg;
		} else if ( !bForceLogin) { // IsSessionTimeout() && 
			if ( Login() ) {
				//防止进入死循环(用户名密码错误?),增加参数bForceLogin
				return GetServiceCfg( true );
			}
		}
		return "";
	}
}

//采用Post方式登录Domino服务器
bool CDominoHandler::Login(  CString strUserName, CString strPassword )
{
	//退出先
	Logout();

	//重设服务请求计数器
	ResetRequest();

	//设置用户名/密码
	if ( strUserName != "" ) m_strUserName = strUserName;
	if ( strPassword != "" ) m_strPassword = strPassword;

	//发送登陆请求
	m_oReqParm.nHttpVerb = CHttpConnection::HTTP_VERB_POST;
	m_oReqParm.sPostData = (
			"%75%73%45%52%6E%41%6D%65="        + CURLEncode::URLEncode(m_strUserName)		//usERnAme
		+	"&%50%41%73%53%77%6F%52%64="       + CURLEncode::URLEncode(m_strPassword)		//PAsSwoRd
		+	"&%72%45%44%69%72%45%63%54%74%4F=" + CURLEncode::URLEncode(m_strDominoServicePath)	//rEDirEcTtO
	);
	m_oReqParm.sUrl = "names.nsf?login";
	
	//直接GET,过于容易泄漏用户/密码
	//m_oReqParm.sUrl = "names.nsf?login&username=" + m_strUserName + "&password=" + m_strPassword + "&redirectto=" + DOMINO_SERVLET_PATH;
	//m_oReqParm.nHttpVerb = CHttpConnection::HTTP_VERB_GET;

#ifdef _DEBUG
	CLog::WriteLine( "用户登录:" +  m_strUserName + ";服务器:"+ this->m_strServerName );
#endif

	sendRequest( true );

	//判断是否登陆成功
	//if ( IsRequestSuccessed() ) CLog::WriteLine("login succ" + m_oReqParm.out_sRet);
	return IsRequestSuccessed();

	//m_oReqParm.sPostData = "Username=" + m_strUserName + "&password=" + m_strPassword + "&RedirectTo=" + DOMINO_SERVLET_PATH;
}

//注销
void CDominoHandler::Logout()
{
	//有过返回结果,即访问过服务器,则发送注销登录命令
	if ( GetRequestResult() != "" ) {
		m_oReqParm.nHttpVerb = NULL;
		m_oReqParm.sPostData = "";
		m_oReqParm.sUrl = "names.nsf?logout";
#ifdef _DEBUG
	CLog::WriteLine( "用户注销:" +  m_strUserName + ";服务器:"+ this->m_strServerName );
#endif
		sendRequest( true );	//若不等待线程结束,则可能造成退出时异常
	}
}

//连接到服务器,请求服务结果,并解析后返回
CString CDominoHandler::GetServiceMsg( bool bForceLogin )
{
#ifdef _DEBUG
	CLog::WriteLine( "请求服务:" + this->m_strServerName );
#endif

	//初始化结果
	m_rgstrServiceResultMsg[0] = "";

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -