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

📄 pop3store.cpp

📁 MIME解析的代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//// VMime library (http://www.vmime.org)// Copyright (C) 2002-2008 Vincent Richard <vincent@vincent-richard.net>//// 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, write to the Free Software Foundation, Inc.,// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.//// Linking this library statically or dynamically with other modules is making// a combined work based on this library.  Thus, the terms and conditions of// the GNU General Public License cover the whole combination.//#include "vmime/net/pop3/POP3Store.hpp"#include "vmime/net/pop3/POP3Folder.hpp"#include "vmime/exception.hpp"#include "vmime/platform.hpp"#include "vmime/messageId.hpp"#include "vmime/security/digest/messageDigestFactory.hpp"#include "vmime/utility/filteredStream.hpp"#include "vmime/utility/stringUtils.hpp"#include "vmime/net/defaultConnectionInfos.hpp"#if VMIME_HAVE_SASL_SUPPORT	#include "vmime/security/sasl/SASLContext.hpp"#endif // VMIME_HAVE_SASL_SUPPORT#if VMIME_HAVE_TLS_SUPPORT	#include "vmime/net/tls/TLSSession.hpp"	#include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"#endif // VMIME_HAVE_TLS_SUPPORT#include <algorithm>// Helpers for service properties#define GET_PROPERTY(type, prop) \	(getInfos().getPropertyValue <type>(getSession(), \		dynamic_cast <const POP3ServiceInfos&>(getInfos()).getProperties().prop))#define HAS_PROPERTY(prop) \	(getInfos().hasProperty(getSession(), \		dynamic_cast <const POP3ServiceInfos&>(getInfos()).getProperties().prop))namespace vmime {namespace net {namespace pop3 {POP3Store::POP3Store(ref <session> sess, ref <security::authenticator> auth, const bool secured)	: store(sess, getInfosInstance(), auth), m_socket(NULL),	  m_authentified(false), m_timeoutHandler(NULL),	  m_isPOP3S(secured), m_secured(false){}POP3Store::~POP3Store(){	try	{		if (isConnected())			disconnect();		else if (m_socket)			internalDisconnect();	}	catch (vmime::exception&)	{		// Ignore	}}const string POP3Store::getProtocolName() const{	return "pop3";}ref <folder> POP3Store::getDefaultFolder(){	if (!isConnected())		throw exceptions::illegal_state("Not connected");	return vmime::create <POP3Folder>(folder::path(folder::path::component("INBOX")),		thisRef().dynamicCast <POP3Store>());}ref <folder> POP3Store::getRootFolder(){	if (!isConnected())		throw exceptions::illegal_state("Not connected");	return vmime::create <POP3Folder>(folder::path(),		thisRef().dynamicCast <POP3Store>());}ref <folder> POP3Store::getFolder(const folder::path& path){	if (!isConnected())		throw exceptions::illegal_state("Not connected");	return vmime::create <POP3Folder>(path,		thisRef().dynamicCast <POP3Store>());}bool POP3Store::isValidFolderName(const folder::path::component& /* name */) const{	return true;}void POP3Store::connect(){	if (isConnected())		throw exceptions::already_connected();	const string address = GET_PROPERTY(string, PROPERTY_SERVER_ADDRESS);	const port_t port = GET_PROPERTY(port_t, PROPERTY_SERVER_PORT);	// Create the time-out handler	if (getTimeoutHandlerFactory())		m_timeoutHandler = getTimeoutHandlerFactory()->create();	// Create and connect the socket	m_socket = getSocketFactory()->create();#if VMIME_HAVE_TLS_SUPPORT	if (m_isPOP3S)  // dedicated port/POP3S	{		ref <tls::TLSSession> tlsSession =			vmime::create <tls::TLSSession>(getCertificateVerifier());		ref <tls::TLSSocket> tlsSocket =			tlsSession->getSocket(m_socket);		m_socket = tlsSocket;		m_secured = true;		m_cntInfos = vmime::create <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);	}	else#endif // VMIME_HAVE_TLS_SUPPORT	{		m_cntInfos = vmime::create <defaultConnectionInfos>(address, port);	}	m_socket->connect(address, port);	// Connection	//	// eg:  C: <connection to server>	// ---  S: +OK MailSite POP3 Server 5.3.4.0 Ready <36938848.1056800841.634@somewhere.com>	string response;	readResponse(response, false);	if (!isSuccessResponse(response))	{		internalDisconnect();		throw exceptions::connection_greeting_error(response);	}#if VMIME_HAVE_TLS_SUPPORT	// Setup secured connection, if requested	const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)		&& GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);	const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)		&& GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);	if (!m_isPOP3S && tls)  // only if not POP3S	{		try		{			startTLS();		}		// Non-fatal error		catch (exceptions::command_error&)		{			if (tlsRequired)			{				throw;			}			else			{				// TLS is not required, so don't bother			}		}		// Fatal error		catch (...)		{			throw;		}	}#endif // VMIME_HAVE_TLS_SUPPORT	// Start authentication process	authenticate(messageId(response));}void POP3Store::authenticate(const messageId& randomMID){	getAuthenticator()->setService(thisRef().dynamicCast <service>());#if VMIME_HAVE_SASL_SUPPORT	// First, try SASL authentication	if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))	{		try		{			authenticateSASL();			m_authentified = true;			return;		}		catch (exceptions::authentication_error& e)		{			if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))			{				// Can't fallback on APOP/normal authentication				internalDisconnect();				throw e;			}			else			{				// Ignore, will try APOP/normal authentication			}		}		catch (exception& e)		{			internalDisconnect();			throw e;		}	}#endif // VMIME_HAVE_SASL_SUPPORT	// Secured authentication with APOP (if requested and if available)	//	// eg:  C: APOP vincent <digest>	// ---  S: +OK vincent is a valid mailbox	const string username = getAuthenticator()->getUsername();	const string password = getAuthenticator()->getPassword();	string response;	if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP))	{		if (randomMID.getLeft().length() != 0 &&		    randomMID.getRight().length() != 0)		{			// <digest> is the result of MD5 applied to "<message-id>password"			ref <security::digest::messageDigest> md5 =				security::digest::messageDigestFactory::getInstance()->create("md5");			md5->update(randomMID.generate() + password);			md5->finalize();			sendRequest("APOP " + username + " " + md5->getHexDigest());			readResponse(response, false);			if (isSuccessResponse(response))			{				m_authentified = true;				return;			}			else			{				// Some servers close the connection after an unsuccessful APOP				// command, so the fallback may not always work...				//				// S: +OK Qpopper (version 4.0.5) at xxx starting.  <30396.1126730747@xxx>				// C: APOP plop c5e0a87d088ec71d60e32692d4c5bdf4				// S: -ERR [AUTH] Password supplied for "plop" is incorrect.				// S: +OK Pop server at xxx signing off.				// [Connection closed by foreign host.]				if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))				{					// Can't fallback on basic authentication					internalDisconnect();					throw exceptions::authentication_error(response);				}				// Ensure connection is valid (cf. note above)				try				{					string response2;					sendRequest("NOOP");					readResponse(response2, false);				}				catch (exceptions::socket_exception&)				{					internalDisconnect();					throw exceptions::authentication_error(response);				}			}		}		else		{			// APOP not supported			if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))			{				// Can't fallback on basic authentication				internalDisconnect();				throw exceptions::authentication_error("APOP not supported");			}		}	}	// Basic authentication	//	// eg:  C: USER vincent	// ---  S: +OK vincent is a valid mailbox	//	//      C: PASS couic	//      S: +OK vincent's maildrop has 2 messages (320 octets)	sendRequest("USER " + username);	readResponse(response, false);	if (!isSuccessResponse(response))	{		internalDisconnect();		throw exceptions::authentication_error(response);	}	sendRequest("PASS " + password);	readResponse(response, false);	if (!isSuccessResponse(response))	{		internalDisconnect();		throw exceptions::authentication_error(response);	}	m_authentified = true;}#if VMIME_HAVE_SASL_SUPPORTvoid POP3Store::authenticateSASL(){	if (!getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>())		throw exceptions::authentication_error("No SASL authenticator available.");	std::vector <string> capa = getCapabilities();	std::vector <string> saslMechs;	for (unsigned int i = 0 ; i < capa.size() ; ++i)	{		const string& x = capa[i];		// C: CAPA		// S: +OK List of capabilities follows		// S: LOGIN-DELAY 0		// S: PIPELINING		// S: UIDL		// S: ...		// S: SASL DIGEST-MD5 CRAM-MD5   <-----		// S: EXPIRE NEVER		// S: ...		if (x.length() > 5 &&		    (x[0] == 'S' || x[0] == 's') &&		    (x[1] == 'A' || x[1] == 'a') &&		    (x[2] == 'S' || x[2] == 's') &&		    (x[3] == 'L' || x[3] == 'l') &&		    (x[4] == ' ' || x[4] == '\t'))		{			const string list(x.begin() + 5, x.end());			std::istringstream iss(list);			string mech;			while (iss >> mech)				saslMechs.push_back(mech);		}	}	if (saslMechs.empty())		throw exceptions::authentication_error("No SASL mechanism available.");	std::vector <ref <security::sasl::SASLMechanism> > mechList;	ref <security::sasl::SASLContext> saslContext =		vmime::create <security::sasl::SASLContext>();	for (unsigned int i = 0 ; i < saslMechs.size() ; ++i)	{		try		{			mechList.push_back				(saslContext->createMechanism(saslMechs[i]));		}		catch (exceptions::no_such_mechanism&)		{			// Ignore mechanism		}	}	if (mechList.empty())		throw exceptions::authentication_error("No SASL mechanism available.");	// Try to suggest a mechanism among all those supported	ref <security::sasl::SASLMechanism> suggestedMech =		saslContext->suggestMechanism(mechList);	if (!suggestedMech)		throw exceptions::authentication_error("Unable to suggest SASL mechanism.");	// Allow application to choose which mechanisms to use	mechList = getAuthenticator().dynamicCast <security::sasl::SASLAuthenticator>()->		getAcceptableMechanisms(mechList, suggestedMech);	if (mechList.empty())		throw exceptions::authentication_error("No SASL mechanism available.");	// Try each mechanism in the list in turn	for (unsigned int i = 0 ; i < mechList.size() ; ++i)	{		ref <security::sasl::SASLMechanism> mech = mechList[i];		ref <security::sasl::SASLSession> saslSession =			saslContext->createSession("pop3", getAuthenticator(), mech);		saslSession->init();		sendRequest("AUTH " + mech->getName());		for (bool cont = true ; cont ; )		{			string response;			readResponse(response, false);			switch (getResponseCode(response))			{			case RESPONSE_OK:			{				m_socket = saslSession->getSecuredSocket(m_socket);				return;			}			case RESPONSE_READY:			{				byte_t* challenge = 0;				int challengeLen = 0;				byte_t* resp = 0;				int respLen = 0;				try				{					// Extract challenge					stripResponseCode(response, response);					saslContext->decodeB64(response, &challenge, &challengeLen);					// Prepare response					saslSession->evaluateChallenge						(challenge, challengeLen, &resp, &respLen);					// Send response					sendRequest(saslContext->encodeB64(resp, respLen));				}				catch (exceptions::sasl_exception& e)				{					if (challenge)					{						delete [] challenge;						challenge = NULL;					}					if (resp)					{						delete [] resp;						resp = NULL;					}					// Cancel SASL exchange					sendRequest("*");				}				catch (...)				{					if (challenge)						delete [] challenge;					if (resp)						delete [] resp;

⌨️ 快捷键说明

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