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

📄 searcher.cpp.svn-base

📁 wince c++ 下 开发的 rss 阅读器源代码
💻 SVN-BASE
字号:
/**
 *  Searcher.cpp
 *
 *  Copyright (C) 2008  David Andrs <pda@jasnapaka.com>
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include "../StdAfx.h"
#include "../prssr.h"
#include "Searcher.h"
#include "../xml/XMLFile.h"
#include "../www/url.h"

#ifdef MYDEBUG
#undef THIS_FILE
static TCHAR THIS_FILE[] = _T(__FILE__);
#include "../debug/crtdbg.h"
#define new MYDEBUG_NEW
#endif

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

////////////////////////////////////////////////////////////////////////////
// CSyndic8ComSearcher class (search on www.syndic8.com)


CSyndic8ComSearcher::CSyndic8ComSearcher(const CString &what, const CString &location) {
	What = what;
	ServerName = _T("www.syndic8.com");
	EndPoint = _T("/xmlrpc.php");
	TempLocation = location;
}

// support functions

BOOL CSyndic8ComSearcher::SendXMLRPCRequest(const CString &strRequest, char **buffer, DWORD *len) {
	LOG0(5, "CSyndic8ComSearcher::SendXMLRPCRequest(,,)");

	State = SEARCH_STATE_CONNECTING;
	BOOL ret = FALSE;
	if (HttpConnection.Open(INET_SERVICE_HTTP, ServerName, 80)) {
		State = SEARCH_STATE_CONNECTED;
		CHttpRequest *request = HttpConnection.CreateRequest(EndPoint, HTTP_METHOD_POST);
		if (request != NULL) {
			// set the request body
			request->SetBody(strRequest);

			// add necessary headers
			request->SetHeader(_T("Content-Type"), _T("text/xml"));
			request->SetHeader(_T("Content-Length"), strRequest.GetLength());

			// send the request
			State = SEARCH_STATE_SENDING_REQUEST;
			HttpConnection.SendRequest(request);

			// get response
			State = SEARCH_STATE_RECEIVING_RESPONSE;
			CHttpResponse *response = HttpConnection.ReceiveResponse();
			if (response != NULL) {
				TCHAR tempFileName[MAX_PATH];
				GetTempFileName(TempLocation, L"rsr", 0, tempFileName);

				State = SEARCH_STATE_DATA_TRANSFER;
				if (HttpConnection.GetFile(response, tempFileName)) {
					// ok, we get the response
					ret = TRUE;
					// read the file
					HANDLE hFile = CreateFile(tempFileName, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
					if (hFile != INVALID_HANDLE_VALUE) {
						DWORD read;
						DWORD size = GetFileSize(hFile, NULL);
						*buffer = new char[size];
						ReadFile(hFile, *buffer, size, &read, NULL);
						*len = read;

						CloseHandle(hFile);
					}
				}
				else {
					// error getting file
					Error = ERROR_GETTING_FILE;
				}

				delete response;
				// delete the temp file
				DeleteFile(tempFileName);
			}
			else {
				// error getting response
				Error = ERROR_GETTING_RESPONSE;
			}

			HttpConnection.Close();
			delete request;
		}
		else {
			// error sending request
			Error = ERROR_SENDING_REQUEST;
		}
	}
	else {
		// can not connect to site
		Error = ERROR_CONNECT;
	}

	PosOffset += HttpConnection.GetDownloadedFileSize();

	return ret;
}

BOOL CSyndic8ComSearcher::IsChildNode(CXmlNode *parent, CXmlNode *&child, const CString &tagName) {
	LOG1(5, "CSyndic8ComSearcher::IsChildNode(%p, ,)", parent);

	if (parent == NULL)
		return FALSE;

	POSITION pos = parent->GetFirstChildPos();
	if (pos != NULL) {
		child = parent->GetNextChild(pos);
		if (child != NULL) {
			CString childTagName = child->GetName();
			if (childTagName.Compare(tagName) == 0)
				return TRUE;
		}
	}

	return FALSE;
}

BOOL CSyndic8ComSearcher::ParseArray(CXmlNode *value, CList<CXmlNode *, CXmlNode *> &listValues) {
	LOG1(5, "CSyndic8ComSearcher::ParseArray(%p,)", value);

	if (value == NULL)
		return FALSE;

	// check <array> tag
	CXmlNode *array = NULL;
	if (IsChildNode(value, array, _T("array"))) {
		// check <data> tag
		CXmlNode *data = NULL;
		if (IsChildNode(array, data, _T("data"))) {
			// get list of <value> tags
			// iterate the array
			POSITION pos = data->GetFirstChildPos();
			while (pos != NULL) {
				// <value> tag
				CXmlNode *value = data->GetNextChild(pos);
				if (value != NULL) {
					CString tagName = value->GetName();
					if (tagName.Compare(_T("value")) == 0) {
						// get child node of <value> tag
						POSITION pos = value->GetFirstChildPos();
						if (pos != NULL) {
							CXmlNode *node = value->GetNextChild(pos);
							// save it to the list
							listValues.AddTail(node);
						}
					}
				}

				PosOffset += 100;
			}
		}
		else
			return FALSE;
	}
	else
		return FALSE;

	return TRUE;
}

// search functions

BOOL CSyndic8ComSearcher::FindFeeds(char **buffer, DWORD *len, int limit) {
	LOG0(5, "CSyndic8ComSearcher::FindFeeds()");

	// create XML-RPC request
	CString sRequest;

	sRequest += _T("<?xml version=\"1.0\"?>\r\n");
	sRequest += _T("<methodCall>\r\n");
	sRequest += _T("\t<methodName>syndic8.FindFeeds</methodName>\r\n");
	sRequest += _T("\t<params>\r\n");

	sRequest += _T("\t\t<param><value><string>\r\n");		// search string
	sRequest += What;
	sRequest += _T("</string></value></param>\r\n");
//	sRequest += _T("\t\t<param><value><string>headlines_rank</string></value></param>\r\n");	// sort by
	sRequest += _T("\t\t<param><value><string>views</string></value></param>\r\n");			// sort by
//	sRequest += _T("\t\t<param><value><string>sitename</string></value></param>\r\n");		// sort by

	// number of items in the result
	CString sLimit;
	sLimit.Format(_T("\t\t<param><value><i4>%d</i4></value></param>\r\n"), limit);
	sRequest += sLimit;
	sRequest += _T("\t</params>\r\n");

	sRequest += _T("</methodCall>\r\n");

	return SendXMLRPCRequest(sRequest, buffer, len);
}

BOOL CSyndic8ComSearcher::QueryFeeds(char **buffer, DWORD *len) {
/*	//
	// * string Feed field to match
	// * string Relational operator
	// * string Value to match
	// * (optional) string Field to sort results
	// * (optional) int Result Limit
	// * (optional) int Result Start
	//

	// create XML-RPC request
	CString sRequest;

	sRequest += _T("<?xml version=\"1.0\"?>\r\n");
	sRequest += _T("<methodCall>\r\n");
	sRequest += _T("\t<methodName>syndic8.QueryFeeds</methodName>\r\n");
	sRequest += _T("\t<params>\r\n");

	sRequest += _T("\t\t<param><value><string>description</string></value></param>\r\n");
	sRequest += _T("\t\t<param><value><string>like</string></value></param>\r\n");
	sRequest += _T("\t\t<param><value><string>\r\n");		// search string
	sRequest += What;
	sRequest += _T("</string></value></param>\r\n");

	sRequest += _T("\t\t<param><value><string>sitename</string></value></param>\r\n");		// sort by

//	number of items in the result
	CString sLimit;
	sLimit.Format(_T("\t\t<param><value><i4>%d</i4></value></param>\r\n"), Config.SearchLimit);
	sRequest += sLimit;
	sRequest += _T("\t</params>\r\n");

	sRequest += _T("</methodCall>\r\n");

	return SendXMLRPCRequest(sRequest, buffer, len);
*/
	return FALSE;
}

BOOL CSyndic8ComSearcher::GetFeedInfo(char **buffer, DWORD *len, CList<int, int> &feedIDs) {
	LOG0(5, "CSyndic8ComSearcher::GetFeedInfo()");

	// create XML-RPC request
	CString sRequest;

	sRequest += _T("<?xml version=\"1.0\"?>\r\n");
	sRequest += _T("<methodCall>\r\n");
	sRequest += _T("\t<methodName>syndic8.GetFeedInfo</methodName>\r\n");
	sRequest += _T("\t<params>\r\n");

	// array
	sRequest += _T("\t\t<param><value><array><data>\r\n");
	// items

	POSITION pos = feedIDs.GetHeadPosition();
	while (pos != NULL) {
		int id = feedIDs.GetNext(pos);

		CString s;
		s.Format(_T("\t\t<value><int>%d</int></value>\r\n"), id);
		sRequest += s;
	}
	sRequest += _T("</data></array></value></param>\r\n");

	sRequest += _T("\t</params>\r\n");
	sRequest += _T("</methodCall>\r\n");

	return SendXMLRPCRequest(sRequest, buffer, len);
}

BOOL CSyndic8ComSearcher::ParseFindResponse(char *xmlResponse, int responseLen, CList<int, int> &feedIDs) {
	LOG0(5, "CSyndic8ComSearcher::ParseFindResponse()");

	BOOL ret = FALSE;

	CXmlFile xml;
	xml.LoadFromMemory(xmlResponse, responseLen);

	CXmlNode *rootNode = xml.GetRootNode();
	if (rootNode != NULL && rootNode->GetName().Compare(_T("methodResponse")) == 0) {
		// check <params> tag
		CXmlNode *params = NULL;
		if (IsChildNode(rootNode, params, _T("params"))) {
			// check <param> tag
			CXmlNode *param = NULL;
			if (IsChildNode(params, param, _T("param"))) {
				// check <value> tag
				CXmlNode *value = NULL;
				if (IsChildNode(param, value, _T("value"))) {
					CList<CXmlNode *, CXmlNode *> listValues;
					if (ParseArray(value, listValues)) {
						// iterate through list
						POSITION pos = listValues.GetHeadPosition();
						while (pos != NULL) {
							CXmlNode *node = listValues.GetNext(pos);

							int id = 0;
							if (swscanf(node->GetValue(), _T("%d"), &id) == 1)
								feedIDs.AddTail(id);

							PosOffset += 1000;
						}

						ret = TRUE;
					}
				}
			}
		}
	}

	return ret;
}

BOOL CSyndic8ComSearcher::ParseFeedInfoStruct(CXmlNode *structNode, CSearchResultItem *sritem) {
	LOG0(5, "CSyndic8ComSearcher::ParseFeedInfoStruct()");

	if (structNode == NULL || sritem == NULL)
		return FALSE;

	POSITION pos = structNode->GetFirstChildPos();
	while (pos != NULL) {
		// <member> tag
		CXmlNode *member = structNode->GetNextChild(pos);
		if (member != NULL && member->GetName().Compare(_T("member")) == 0) {
			CString strMemberName;
			CString strMemberValue;

			// iterate <member> child nodes (obtain <name> and <value> tag values)
			POSITION pos = member->GetFirstChildPos();
			while (pos != NULL) {
				CXmlNode *child = member->GetNextChild(pos);
				if (child != NULL) {
					CString tagName = child->GetName();
					if (tagName.Compare(_T("name")) == 0) {
						strMemberName = child->GetValue();
					}
					else if (tagName.Compare(_T("value")) == 0) {
						POSITION posV = child->GetFirstChildPos();
						if (posV != NULL) {
							CXmlNode *type = child->GetNextChild(posV);
							if (type != NULL) {
								strMemberValue = type->GetValue();
							}
						}
						else {
							strMemberValue = child->GetValue();
						}
					}
				}

				PosOffset += 1000;
			}

			// did we find all?
			if (!strMemberValue.IsEmpty()) {
				if (strMemberName.Compare(_T("sitename")) == 0) {
					sritem->SiteName = strMemberValue;
				}
				else if (strMemberName.Compare(_T("dataurl")) == 0) {
					sritem->XMLURL = strMemberValue;
				}
				else if (strMemberName.Compare(_T("description")) == 0) {
					sritem->Description = strMemberValue;
				}
			}
		}
	}

	// we need at least site name and feed url
	if (sritem->XMLURL.IsEmpty() || sritem->SiteName.IsEmpty())
		return FALSE;
	else
		return TRUE;
}

BOOL CSyndic8ComSearcher::ParseFeedInfoResponse(char *xmlResponse, int responseLen, CList<CSearchResultItem *, CSearchResultItem *> &searchResult) {
	LOG0(5, "CSyndic8ComSearcher::ParseFeedInfoResponse()");

	BOOL ret = FALSE;

	CXmlFile xml;
	xml.LoadFromMemory(xmlResponse, responseLen);

	CXmlNode *rootNode = xml.GetRootNode();
	if (rootNode != NULL && rootNode->GetName().Compare(_T("methodResponse")) == 0) {
		// check <params> tag
		CXmlNode *params = NULL;
		if (IsChildNode(rootNode, params, _T("params"))) {
			// check <param> tag
			CXmlNode *param = NULL;
			if (IsChildNode(params, param, _T("param"))) {
				// check <value> tag
				CXmlNode *value = NULL;
				if (IsChildNode(param, value, _T("value"))) {
					CList<CXmlNode *, CXmlNode *> listValues;
					if (ParseArray(value, listValues)) {
						// iterate through list
						POSITION pos = listValues.GetHeadPosition();
						while (pos != NULL) {
							CXmlNode *node = listValues.GetNext(pos);

							CSearchResultItem *srItem = new CSearchResultItem;
							if (ParseFeedInfoStruct(node, srItem)) {
								// ok, we got it!
								searchResult.AddTail(srItem);
							}
							else {
								delete srItem;
							}

							PosOffset += 1000;
						}

						ret = TRUE;
					}
				}
			}
		}
	}

	return ret;
}

BOOL CSyndic8ComSearcher::Search(int limit, CList<CSearchResultItem *, CSearchResultItem *> &searchResult) {
	LOG0(1, "CSyndic8ComSearcher::Search()");

	BOOL ret = FALSE;

	PosOffset = 0;

	// find feeds
	char *findFeedResponse = NULL;		// XML file (start with some amount)
	DWORD findFeedResponseLen = 0;

	if (FindFeeds(&findFeedResponse, &findFeedResponseLen, limit)) {
		// parse the result
		CList<int, int> feedIDs;
		if (ParseFindResponse(findFeedResponse, findFeedResponseLen, feedIDs)) {
			// get info about found feeds
			char *getFeedInfoResponse = NULL;			// XML file  (start with some amount)
			DWORD getFeedInfoResponseLen = 0;

			if (feedIDs.GetCount() > 0 && GetFeedInfo(&getFeedInfoResponse, &getFeedInfoResponseLen, feedIDs)) {
				// parse the result (and fill the 'searchResult' variable)
				if (ParseFeedInfoResponse(getFeedInfoResponse, getFeedInfoResponseLen, searchResult)) {
					ret = TRUE;
					State = SEARCH_STATE_CLOSED;
				}
				else {
					Error = ERROR_XML_RPC_RESPONSE;
				}
			}

			if (getFeedInfoResponse != NULL)
				delete [] getFeedInfoResponse;
		}
		else {
			Error = ERROR_XML_RPC_RESPONSE;
		}
	}

	if (findFeedResponse != NULL)
		delete [] findFeedResponse;

	return ret;
}

void CSyndic8ComSearcher::Terminate() {
	HttpConnection.Terminate();
}

CString CSyndic8ComSearcher::GetErrorMsg() {
	CString errorMsg;

	switch (Error) {
		case ERROR_CONNECT:	          errorMsg.LoadString(IDS_ERROR_CONNECT); break;
		case ERROR_SENDING_REQUEST:  errorMsg.LoadString(IDS_ERROR_SENDING_REQUEST); break;
		case ERROR_GETTING_RESPONSE: errorMsg.LoadString(IDS_RESPONSE_ERROR); break;
		case ERROR_GETTING_FILE:     errorMsg.LoadString(IDS_ERROR_GETTING_FILE); break;
		case ERROR_XML_RPC_RESPONSE: errorMsg.LoadString(IDS_ERROR_XML_RPC_RESPONSE); break;
	}
	return errorMsg;
}

⌨️ 快捷键说明

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