aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vmime/exception.cpp13
-rw-r--r--src/vmime/exception.hpp17
-rw-r--r--src/vmime/net/imap/IMAPConnection.cpp10
-rw-r--r--src/vmime/net/imap/IMAPFolder.cpp7
-rw-r--r--src/vmime/net/pop3/POP3Connection.cpp10
-rw-r--r--src/vmime/net/pop3/POP3Folder.cpp3
-rw-r--r--src/vmime/net/pop3/POP3Message.cpp2
-rw-r--r--src/vmime/net/smtp/SMTPConnection.cpp40
-rw-r--r--src/vmime/net/socket.hpp6
-rw-r--r--src/vmime/net/tls/TLSSocket.hpp2
-rw-r--r--src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp36
-rw-r--r--src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp5
-rw-r--r--src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp85
-rw-r--r--src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp6
-rw-r--r--src/vmime/platforms/posix/posixSocket.cpp6
-rw-r--r--src/vmime/platforms/posix/posixSocket.hpp2
-rw-r--r--src/vmime/platforms/windows/windowsSocket.cpp6
-rw-r--r--src/vmime/platforms/windows/windowsSocket.hpp2
-rw-r--r--src/vmime/security/sasl/SASLSocket.cpp6
-rw-r--r--src/vmime/security/sasl/SASLSocket.hpp2
-rw-r--r--src/vmime/textPartFactory.cpp2
-rw-r--r--src/vmime/utility/path.cpp47
-rw-r--r--src/vmime/utility/path.hpp19
-rw-r--r--tests/net/imap/IMAPParserTest.cpp37
-rw-r--r--tests/testUtils.cpp6
-rw-r--r--tests/testUtils.hpp2
-rw-r--r--tests/utility/pathTest.cpp40
27 files changed, 322 insertions, 97 deletions
diff --git a/src/vmime/exception.cpp b/src/vmime/exception.cpp
index 042ac4f4..dff7d497 100644
--- a/src/vmime/exception.cpp
+++ b/src/vmime/exception.cpp
@@ -328,6 +328,19 @@ const char* socket_exception::name() const throw() { return "socket_exception";
//
+// socket_not_connected_exception
+//
+
+socket_not_connected_exception::~socket_not_connected_exception() throw() {}
+socket_not_connected_exception::socket_not_connected_exception(const string& what, const exception& other)
+ : socket_exception(what.empty()
+ ? "Socket is not connected." : what, other) {}
+
+exception* socket_not_connected_exception::clone() const { return new socket_not_connected_exception(*this); }
+const char* socket_not_connected_exception::name() const throw() { return "socket_not_connected_exception"; }
+
+
+//
// connection_error
//
diff --git a/src/vmime/exception.hpp b/src/vmime/exception.hpp
index e2afcc62..3c547756 100644
--- a/src/vmime/exception.hpp
+++ b/src/vmime/exception.hpp
@@ -370,6 +370,23 @@ public:
};
+/** Socket not connected: you are trying to write to/read from a socket which
+ * is not connected to a peer.
+ */
+
+class VMIME_EXPORT socket_not_connected_exception : public socket_exception
+{
+public:
+
+ socket_not_connected_exception(const string& what = "", const exception& other = NO_EXCEPTION);
+ ~socket_not_connected_exception() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+
+};
+
+
/** Error while connecting to the server: this may be a DNS resolution error
* or a connection error (for example, time-out while connecting).
*/
diff --git a/src/vmime/net/imap/IMAPConnection.cpp b/src/vmime/net/imap/IMAPConnection.cpp
index bab4e58b..5e6f6f8f 100644
--- a/src/vmime/net/imap/IMAPConnection.cpp
+++ b/src/vmime/net/imap/IMAPConnection.cpp
@@ -234,23 +234,23 @@ void IMAPConnection::authenticate()
authenticateSASL();
return;
}
- catch (exceptions::authentication_error& e)
+ catch (exceptions::authentication_error&)
{
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
{
// Can't fallback on normal authentication
internalDisconnect();
- throw e;
+ throw;
}
else
{
// Ignore, will try normal authentication
}
}
- catch (exception& e)
+ catch (exception&)
{
internalDisconnect();
- throw e;
+ throw;
}
}
#endif // VMIME_HAVE_SASL_SUPPORT
@@ -482,7 +482,7 @@ void IMAPConnection::startTLS()
shared_ptr <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
- tlsSocket->handshake(m_timeoutHandler);
+ tlsSocket->handshake();
m_socket = tlsSocket;
m_parser->setSocket(m_socket);
diff --git a/src/vmime/net/imap/IMAPFolder.cpp b/src/vmime/net/imap/IMAPFolder.cpp
index 343ec35e..25b7d760 100644
--- a/src/vmime/net/imap/IMAPFolder.cpp
+++ b/src/vmime/net/imap/IMAPFolder.cpp
@@ -92,9 +92,6 @@ int IMAPFolder::getMode() const
const folderAttributes IMAPFolder::getAttributes()
{
- if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
-
// Root folder
if (m_path.isEmpty())
{
@@ -1124,7 +1121,7 @@ messageSet IMAPFolder::addMessage
const IMAPParser::resp_text_code* respTextCode =
finalResp->response_done()->response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
- if (respTextCode->type() == IMAPParser::resp_text_code::APPENDUID)
+ if (respTextCode && respTextCode->type() == IMAPParser::resp_text_code::APPENDUID)
return IMAPUtils::buildMessageSet(respTextCode->uid_set());
return messageSet::empty();
@@ -1266,7 +1263,7 @@ messageSet IMAPFolder::copyMessages(const folder::path& dest, const messageSet&
const IMAPParser::resp_text_code* respTextCode =
resp->response_done()->response_tagged()->resp_cond_state()->resp_text()->resp_text_code();
- if (respTextCode->type() == IMAPParser::resp_text_code::COPYUID)
+ if (respTextCode && respTextCode->type() == IMAPParser::resp_text_code::COPYUID)
return IMAPUtils::buildMessageSet(respTextCode->uid_set2());
return messageSet::empty();
diff --git a/src/vmime/net/pop3/POP3Connection.cpp b/src/vmime/net/pop3/POP3Connection.cpp
index 5fa923f4..f5a1a448 100644
--- a/src/vmime/net/pop3/POP3Connection.cpp
+++ b/src/vmime/net/pop3/POP3Connection.cpp
@@ -233,23 +233,23 @@ void POP3Connection::authenticate(const messageId& randomMID)
m_authenticated = true;
return;
}
- catch (exceptions::authentication_error& e)
+ catch (exceptions::authentication_error&)
{
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
{
// Can't fallback on APOP/normal authentication
internalDisconnect();
- throw e;
+ throw;
}
else
{
// Ignore, will try APOP/normal authentication
}
}
- catch (exception& e)
+ catch (exception&)
{
internalDisconnect();
- throw e;
+ throw;
}
}
#endif // VMIME_HAVE_SASL_SUPPORT
@@ -552,7 +552,7 @@ void POP3Connection::startTLS()
shared_ptr <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
- tlsSocket->handshake(m_timeoutHandler);
+ tlsSocket->handshake();
m_socket = tlsSocket;
diff --git a/src/vmime/net/pop3/POP3Folder.cpp b/src/vmime/net/pop3/POP3Folder.cpp
index 56aeae6e..354dad2a 100644
--- a/src/vmime/net/pop3/POP3Folder.cpp
+++ b/src/vmime/net/pop3/POP3Folder.cpp
@@ -83,9 +83,6 @@ int POP3Folder::getMode() const
const folderAttributes POP3Folder::getAttributes()
{
- if (!isOpen())
- throw exceptions::illegal_state("Folder not open");
-
folderAttributes attribs;
if (m_path.isEmpty())
diff --git a/src/vmime/net/pop3/POP3Message.cpp b/src/vmime/net/pop3/POP3Message.cpp
index 08523611..ff1aa88f 100644
--- a/src/vmime/net/pop3/POP3Message.cpp
+++ b/src/vmime/net/pop3/POP3Message.cpp
@@ -95,7 +95,7 @@ bool POP3Message::isExpunged() const
int POP3Message::getFlags() const
{
- int flags = FLAG_RECENT;
+ int flags = 0;
if (m_deleted)
flags |= FLAG_DELETED;
diff --git a/src/vmime/net/smtp/SMTPConnection.cpp b/src/vmime/net/smtp/SMTPConnection.cpp
index e0b5bc68..a45f9149 100644
--- a/src/vmime/net/smtp/SMTPConnection.cpp
+++ b/src/vmime/net/smtp/SMTPConnection.cpp
@@ -284,7 +284,7 @@ void SMTPConnection::authenticate()
getAuthenticator()->setService(m_transport.lock());
#if VMIME_HAVE_SASL_SUPPORT
- // First, try SASL authentication
+ // Try SASL authentication
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL))
{
try
@@ -294,23 +294,10 @@ void SMTPConnection::authenticate()
m_authenticated = true;
return;
}
- catch (exceptions::authentication_error& e)
- {
- if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK))
- {
- // Can't fallback on normal authentication
- internalDisconnect();
- throw e;
- }
- else
- {
- // Ignore, will try normal authentication
- }
- }
- catch (exception& e)
+ catch (exception&)
{
internalDisconnect();
- throw e;
+ throw;
}
}
#endif // VMIME_HAVE_SASL_SUPPORT
@@ -487,7 +474,7 @@ void SMTPConnection::startTLS()
shared_ptr <tls::TLSSocket> tlsSocket =
tlsSession->getSocket(m_socket);
- tlsSocket->handshake(m_timeoutHandler);
+ tlsSocket->handshake();
m_socket = tlsSocket;
@@ -522,16 +509,19 @@ void SMTPConnection::disconnect()
void SMTPConnection::internalDisconnect()
{
- try
+ if (isConnected())
{
- sendRequest(SMTPCommand::QUIT());
+ try
+ {
+ sendRequest(SMTPCommand::QUIT());
- // Do not wait for server response. This is contrary to the RFC, but
- // some servers never send a response to a QUIT command.
- }
- catch (exception&)
- {
- // Not important
+ // Do not wait for server response. This is contrary to the RFC, but
+ // some servers never send a response to a QUIT command.
+ }
+ catch (exception&)
+ {
+ // Not important
+ }
}
m_socket->disconnect();
diff --git a/src/vmime/net/socket.hpp b/src/vmime/net/socket.hpp
index 537c34bb..7f878a73 100644
--- a/src/vmime/net/socket.hpp
+++ b/src/vmime/net/socket.hpp
@@ -141,6 +141,12 @@ public:
*/
virtual const string getPeerAddress() const = 0;
+ /** Return the timeout handler associated with this socket.
+ *
+ * @return timeout handler, or NULL if none is set
+ */
+ virtual shared_ptr <timeoutHandler> getTimeoutHandler() = 0;
+
protected:
socket() { }
diff --git a/src/vmime/net/tls/TLSSocket.hpp b/src/vmime/net/tls/TLSSocket.hpp
index e2668ad4..ec3a83ef 100644
--- a/src/vmime/net/tls/TLSSocket.hpp
+++ b/src/vmime/net/tls/TLSSocket.hpp
@@ -67,7 +67,7 @@ public:
* during the negociation process, exceptions::operation_timed_out
* if a time-out occurs
*/
- virtual void handshake(shared_ptr <timeoutHandler> toHandler = null) = 0;
+ virtual void handshake() = 0;
/** Return the peer's certificate (chain) as sent by the peer.
*
diff --git a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp
index edc8811a..13b7eb24 100644
--- a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp
+++ b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp
@@ -87,11 +87,17 @@ TLSSocket_GnuTLS::~TLSSocket_GnuTLS()
void TLSSocket_GnuTLS::connect(const string& address, const port_t port)
{
- m_wrapped->connect(address, port);
-
- handshake(null);
+ try
+ {
+ m_wrapped->connect(address, port);
- m_connected = true;
+ handshake();
+ }
+ catch (...)
+ {
+ disconnect();
+ throw;
+ }
}
@@ -132,6 +138,12 @@ const string TLSSocket_GnuTLS::getPeerAddress() const
}
+shared_ptr <timeoutHandler> TLSSocket_GnuTLS::getTimeoutHandler()
+{
+ return m_wrapped->getTimeoutHandler();
+}
+
+
void TLSSocket_GnuTLS::receive(string& buffer)
{
const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
@@ -239,14 +251,15 @@ unsigned int TLSSocket_GnuTLS::getStatus() const
}
-void TLSSocket_GnuTLS::handshake(shared_ptr <timeoutHandler> toHandler)
+void TLSSocket_GnuTLS::handshake()
{
+ shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
+
if (toHandler)
toHandler->resetTimeOut();
// Start handshaking process
m_handshaking = true;
- m_toHandler = toHandler;
try
{
@@ -280,13 +293,10 @@ void TLSSocket_GnuTLS::handshake(shared_ptr <timeoutHandler> toHandler)
catch (...)
{
m_handshaking = false;
- m_toHandler = null;
-
throw;
}
m_handshaking = false;
- m_toHandler = null;
// Verify server's certificate(s)
shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
@@ -338,6 +348,8 @@ ssize_t TLSSocket_GnuTLS::gnutlsPullFunc
// returns -1 and errno is set to EGAIN...
if (sok->m_handshaking)
{
+ shared_ptr <timeoutHandler> toHandler = sok->m_wrapped->getTimeoutHandler();
+
while (true)
{
const ssize_t ret = static_cast <ssize_t>
@@ -355,12 +367,12 @@ ssize_t TLSSocket_GnuTLS::gnutlsPullFunc
}
// Check whether the time-out delay is elapsed
- if (sok->m_toHandler && sok->m_toHandler->isTimeOut())
+ if (toHandler && toHandler->isTimeOut())
{
- if (!sok->m_toHandler->handleTimeOut())
+ if (!toHandler->handleTimeOut())
throw exceptions::operation_timed_out();
- sok->m_toHandler->resetTimeOut();
+ toHandler->resetTimeOut();
}
}
}
diff --git a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
index 885fac13..ddba9d0e 100644
--- a/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
+++ b/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
@@ -54,7 +54,7 @@ public:
~TLSSocket_GnuTLS();
- void handshake(shared_ptr <timeoutHandler> toHandler = null);
+ void handshake();
shared_ptr <security::cert::certificateChain> getPeerCertificates() const;
@@ -78,6 +78,8 @@ public:
const string getPeerName() const;
const string getPeerAddress() const;
+ shared_ptr <timeoutHandler> getTimeoutHandler();
+
private:
void internalThrow();
@@ -99,7 +101,6 @@ private:
byte_t m_buffer[65536];
bool m_handshaking;
- shared_ptr <timeoutHandler> m_toHandler;
exception* m_ex;
diff --git a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp
index 9857b8fb..595a0091 100644
--- a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp
+++ b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp
@@ -87,12 +87,6 @@ TLSSocket_OpenSSL::~TLSSocket_OpenSSL()
try
{
disconnect();
-
- if (m_ssl)
- {
- SSL_free(m_ssl);
- m_ssl = 0;
- }
}
catch (...)
{
@@ -130,32 +124,41 @@ void TLSSocket_OpenSSL::createSSLHandle()
void TLSSocket_OpenSSL::connect(const string& address, const port_t port)
{
- m_wrapped->connect(address, port);
-
- createSSLHandle();
+ try
+ {
+ m_wrapped->connect(address, port);
- handshake(null);
+ createSSLHandle();
- m_connected = true;
+ handshake();
+ }
+ catch (...)
+ {
+ disconnect();
+ throw;
+ }
}
void TLSSocket_OpenSSL::disconnect()
{
- if (m_connected)
+ if (m_ssl)
{
- if (m_ssl)
- {
- // Don't shut down the socket more than once.
- int shutdownState = SSL_get_shutdown(m_ssl);
- bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
+ // Don't shut down the socket more than once.
+ int shutdownState = SSL_get_shutdown(m_ssl);
+ bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
- if (!shutdownSent)
- SSL_shutdown(m_ssl);
- }
+ if (!shutdownSent)
+ SSL_shutdown(m_ssl);
- m_wrapped->disconnect();
+ SSL_free(m_ssl);
+ m_ssl = 0;
+ }
+
+ if (m_connected)
+ {
m_connected = false;
+ m_wrapped->disconnect();
}
}
@@ -184,6 +187,12 @@ const string TLSSocket_OpenSSL::getPeerAddress() const
}
+shared_ptr <timeoutHandler> TLSSocket_OpenSSL::getTimeoutHandler()
+{
+ return m_wrapped->getTimeoutHandler();
+}
+
+
void TLSSocket_OpenSSL::receive(string& buffer)
{
const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
@@ -209,6 +218,9 @@ void TLSSocket_OpenSSL::send(const char* str)
size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count)
{
+ if (!m_ssl)
+ throw exceptions::socket_not_connected_exception();
+
m_status &= ~STATUS_WOULDBLOCK;
int rc = SSL_read(m_ssl, buffer, static_cast <int>(count));
@@ -235,6 +247,9 @@ size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count)
void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count)
{
+ if (!m_ssl)
+ throw exceptions::socket_not_connected_exception();
+
m_status &= ~STATUS_WOULDBLOCK;
for (size_t size = count ; size > 0 ; )
@@ -264,6 +279,9 @@ void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count)
size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count)
{
+ if (!m_ssl)
+ throw exceptions::socket_not_connected_exception();
+
m_status &= ~STATUS_WOULDBLOCK;
int rc = SSL_write(m_ssl, buffer, static_cast <int>(count));
@@ -288,14 +306,17 @@ size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t
}
-void TLSSocket_OpenSSL::handshake(shared_ptr <timeoutHandler> toHandler)
+void TLSSocket_OpenSSL::handshake()
{
+ if (!m_ssl)
+ throw exceptions::socket_not_connected_exception();
+
+ shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
+
if (toHandler)
toHandler->resetTimeOut();
// Start handshaking process
- m_toHandler = toHandler;
-
if (!m_ssl)
createSSLHandle();
@@ -318,25 +339,20 @@ void TLSSocket_OpenSSL::handshake(shared_ptr <timeoutHandler> toHandler)
}
// Check whether the time-out delay is elapsed
- if (m_toHandler && m_toHandler->isTimeOut())
+ if (toHandler && toHandler->isTimeOut())
{
- if (!m_toHandler->handleTimeOut())
+ if (!toHandler->handleTimeOut())
throw exceptions::operation_timed_out();
- m_toHandler->resetTimeOut();
+ toHandler->resetTimeOut();
}
}
}
catch (...)
{
- SSL_free(m_ssl);
- m_ssl = 0;
- m_toHandler = null;
throw;
}
- m_toHandler = null;
-
// Verify server's certificate(s)
shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
@@ -401,6 +417,8 @@ void TLSSocket_OpenSSL::handleError(int rc)
switch (sslError)
{
case SSL_ERROR_ZERO_RETURN:
+
+ disconnect();
return;
case SSL_ERROR_SYSCALL:
@@ -413,8 +431,7 @@ void TLSSocket_OpenSSL::handleError(int rc)
}
else
{
- vmime::string msg;
- std::ostringstream oss(msg);
+ std::ostringstream oss;
oss << "The BIO reported an error: " << rc;
oss.flush();
throw exceptions::tls_exception(oss.str());
diff --git a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
index 410fffcf..5fbed19d 100644
--- a/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
+++ b/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
@@ -58,7 +58,7 @@ public:
~TLSSocket_OpenSSL();
- void handshake(shared_ptr <timeoutHandler> toHandler = null);
+ void handshake();
shared_ptr <security::cert::certificateChain> getPeerCertificates() const;
@@ -82,6 +82,8 @@ public:
const string getPeerName() const;
const string getPeerAddress() const;
+ shared_ptr <timeoutHandler> getTimeoutHandler();
+
private:
static BIO_METHOD sm_customBIOMethod;
@@ -108,8 +110,6 @@ private:
byte_t m_buffer[65536];
- shared_ptr <timeoutHandler> m_toHandler;
-
SSL* m_ssl;
unsigned long m_status;
diff --git a/src/vmime/platforms/posix/posixSocket.cpp b/src/vmime/platforms/posix/posixSocket.cpp
index ab434116..e7eba9f1 100644
--- a/src/vmime/platforms/posix/posixSocket.cpp
+++ b/src/vmime/platforms/posix/posixSocket.cpp
@@ -654,6 +654,12 @@ unsigned int posixSocket::getStatus() const
}
+shared_ptr <net::timeoutHandler> posixSocket::getTimeoutHandler()
+{
+ return m_timeoutHandler;
+}
+
+
//
// posixSocketFactory
diff --git a/src/vmime/platforms/posix/posixSocket.hpp b/src/vmime/platforms/posix/posixSocket.hpp
index 4ec3edec..5d29d710 100644
--- a/src/vmime/platforms/posix/posixSocket.hpp
+++ b/src/vmime/platforms/posix/posixSocket.hpp
@@ -65,6 +65,8 @@ public:
const string getPeerName() const;
const string getPeerAddress() const;
+ shared_ptr <net::timeoutHandler> getTimeoutHandler();
+
protected:
static void throwSocketError(const int err);
diff --git a/src/vmime/platforms/windows/windowsSocket.cpp b/src/vmime/platforms/windows/windowsSocket.cpp
index cb96481a..bd20e5d4 100644
--- a/src/vmime/platforms/windows/windowsSocket.cpp
+++ b/src/vmime/platforms/windows/windowsSocket.cpp
@@ -460,6 +460,12 @@ void windowsSocket::waitForData(const WaitOpType t, bool& timedOut)
}
+shared_ptr <net::timeoutHandler> windowsSocket::getTimeoutHandler()
+{
+ return m_timeoutHandler;
+}
+
+
//
// posixSocketFactory
diff --git a/src/vmime/platforms/windows/windowsSocket.hpp b/src/vmime/platforms/windows/windowsSocket.hpp
index cb8a6e67..31e1488b 100644
--- a/src/vmime/platforms/windows/windowsSocket.hpp
+++ b/src/vmime/platforms/windows/windowsSocket.hpp
@@ -69,6 +69,8 @@ public:
const string getPeerName() const;
const string getPeerAddress() const;
+ shared_ptr <net::timeoutHandler> getTimeoutHandler();
+
protected:
void throwSocketError(const int err);
diff --git a/src/vmime/security/sasl/SASLSocket.cpp b/src/vmime/security/sasl/SASLSocket.cpp
index 12d634c2..541fc904 100644
--- a/src/vmime/security/sasl/SASLSocket.cpp
+++ b/src/vmime/security/sasl/SASLSocket.cpp
@@ -96,6 +96,12 @@ const string SASLSocket::getPeerAddress() const
}
+shared_ptr <net::timeoutHandler> SASLSocket::getTimeoutHandler()
+{
+ return m_wrapped->getTimeoutHandler();
+}
+
+
void SASLSocket::receive(string& buffer)
{
const size_t n = receiveRaw(m_recvBuffer, sizeof(m_recvBuffer));
diff --git a/src/vmime/security/sasl/SASLSocket.hpp b/src/vmime/security/sasl/SASLSocket.hpp
index e52911b4..d2d82411 100644
--- a/src/vmime/security/sasl/SASLSocket.hpp
+++ b/src/vmime/security/sasl/SASLSocket.hpp
@@ -73,6 +73,8 @@ public:
const string getPeerName() const;
const string getPeerAddress() const;
+ shared_ptr <net::timeoutHandler> getTimeoutHandler();
+
private:
shared_ptr <SASLSession> m_session;
diff --git a/src/vmime/textPartFactory.cpp b/src/vmime/textPartFactory.cpp
index 85fea6e4..846a6605 100644
--- a/src/vmime/textPartFactory.cpp
+++ b/src/vmime/textPartFactory.cpp
@@ -62,7 +62,7 @@ shared_ptr <textPart> textPartFactory::create(const mediaType& type)
return ((*it).second)();
}
- throw exceptions::no_factory_available();
+ throw exceptions::no_factory_available("No 'textPart' class registered for media type '" + type.generate() + "'.");
}
diff --git a/src/vmime/utility/path.cpp b/src/vmime/utility/path.cpp
index 59685866..aaa3192e 100644
--- a/src/vmime/utility/path.cpp
+++ b/src/vmime/utility/path.cpp
@@ -261,5 +261,52 @@ path::component& path::getComponentAt(const size_t pos)
}
+// static
+path path::fromString(const string& str, const string& sep, const charset& cset)
+{
+ path p;
+
+ size_t start = 0;
+ size_t end = 0;
+
+ do
+ {
+ end = str.find(sep, start);
+
+ string comp;
+
+ if (end == string::npos)
+ comp = str.substr(start);
+ else
+ comp = str.substr(start, end - start);
+
+ // Skip leading or trailing separators
+ if (comp.length())
+ p.appendComponent(component(comp, cset));
+
+ start = end + 1;
+ }
+ while (end != string::npos);
+
+ return p;
+}
+
+
+const string path::toString(const string& sep, const charset& cset)
+{
+ string str;
+
+ for (size_t i = 0 ; i < m_list.size() ; ++i)
+ {
+ if (i != 0)
+ str += sep;
+
+ str += m_list[i].getConvertedText(cset);
+ }
+
+ return str;
+}
+
+
} // utility
} // vmime
diff --git a/src/vmime/utility/path.hpp b/src/vmime/utility/path.hpp
index 203da246..02fd9ce6 100644
--- a/src/vmime/utility/path.hpp
+++ b/src/vmime/utility/path.hpp
@@ -158,6 +158,25 @@ public:
*/
void renameParent(const path& oldPath, const path& newPath);
+ /** Construct a new path from a string.
+ *
+ * @param str string representation of the path
+ * @param sep separator string (eg: "/")
+ * @param cset charset in which the path is encoded (use the value returned by
+ * vmime::charset::getLocalCharset() to use the default charset of your system)
+ * @return a new path corresponding to the specified string
+ */
+ static path fromString(const string& str, const string& sep, const charset& cset);
+
+ /** Returns a string representation of this path.
+ *
+ * @param sep separator string (eg: "/")
+ * @param cset charset in which to encode the components (use the value returned by
+ * vmime::charset::getLocalCharset() to use the default charset of your system)
+ * @return a string representing this path
+ */
+ const string toString(const string& sep, const charset& cset);
+
private:
list m_list;
diff --git a/tests/net/imap/IMAPParserTest.cpp b/tests/net/imap/IMAPParserTest.cpp
index 30e8f574..e598a548 100644
--- a/tests/net/imap/IMAPParserTest.cpp
+++ b/tests/net/imap/IMAPParserTest.cpp
@@ -31,6 +31,7 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
VMIME_TEST_LIST_BEGIN
VMIME_TEST(testExtraSpaceInCapaResponse)
+ VMIME_TEST(testContinueReqWithoutSpace)
VMIME_TEST_LIST_END
@@ -64,4 +65,40 @@ VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
VASSERT_THROW("strict mode", parser->readResponse(/* literalHandler */ NULL), vmime::exceptions::invalid_response);
}
+ // For Apple iCloud/Exchange IMAP server
+ void testContinueReqWithoutSpace()
+ {
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+ // Some servers do not send SPACE when response text is empty.
+ // IMAP parser should allow this in non-strict mode.
+ //
+ // Eg:
+ //
+ // C: a002 AUTHENTICATE xxx[CR][LF]
+ // S: +[CR][LF]
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ socket->localSend("+\r\n");
+
+ vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
+ vmime::make_shared <vmime::net::imap::IMAPParser>
+ (tag, vmime::dynamicCast <vmime::net::socket>(socket), toh);
+
+ parser->setStrict(false);
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse());
+
+ ++(*tag);
+
+ socket->localSend("+\r\n");
+
+ parser->setStrict(true);
+ VASSERT_THROW("strict mode", parser->readResponse(), vmime::exceptions::invalid_response);
+ }
+
VMIME_TEST_SUITE_END
diff --git a/tests/testUtils.cpp b/tests/testUtils.cpp
index 437b476b..ee642bea 100644
--- a/tests/testUtils.cpp
+++ b/tests/testUtils.cpp
@@ -79,6 +79,12 @@ const vmime::string testSocket::getPeerAddress() const
}
+vmime::shared_ptr <vmime::net::timeoutHandler> testSocket::getTimeoutHandler()
+{
+ return vmime::null;
+}
+
+
void testSocket::receive(vmime::string& buffer)
{
buffer = m_inBuffer;
diff --git a/tests/testUtils.hpp b/tests/testUtils.hpp
index f0ecf454..9e72158a 100644
--- a/tests/testUtils.hpp
+++ b/tests/testUtils.hpp
@@ -263,6 +263,8 @@ public:
const vmime::string getPeerName() const;
const vmime::string getPeerAddress() const;
+ vmime::shared_ptr <vmime::net::timeoutHandler> getTimeoutHandler();
+
/** Send data to client.
*
* @param buffer data to send
diff --git a/tests/utility/pathTest.cpp b/tests/utility/pathTest.cpp
index d0c1c091..ef1b773d 100644
--- a/tests/utility/pathTest.cpp
+++ b/tests/utility/pathTest.cpp
@@ -53,6 +53,10 @@ VMIME_TEST_SUITE_BEGIN(utilityPathTest)
VMIME_TEST(testIsParentOf_EquivalentCharset)
VMIME_TEST(testRenameParent)
+
+ VMIME_TEST(testFromString)
+ VMIME_TEST(testFromString_IgnoreLeadingOrTrailingSep)
+ VMIME_TEST(testToString)
VMIME_TEST_LIST_END
@@ -313,5 +317,41 @@ VMIME_TEST_SUITE_BEGIN(utilityPathTest)
VASSERT_EQ("6", "d", p.getComponentAt(4).getBuffer());
}
+ void testFromString()
+ {
+ path p = path::fromString("ab/cde/f", "/", vmime::charset("my-charset"));
+
+ VASSERT_EQ("count", 3, p.getSize());
+ VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
+ VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
+ VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
+ }
+
+ void testFromString_IgnoreLeadingOrTrailingSep()
+ {
+ path p = path::fromString("//ab/cde/f////", "/", vmime::charset("my-charset"));
+
+ VASSERT_EQ("count", 3, p.getSize());
+ VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
+ VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
+ VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
+ }
+
+ void testToString()
+ {
+ path p;
+ p.appendComponent(comp("ab"));
+ p.appendComponent(comp("cde"));
+ p.appendComponent(comp("f"));
+
+ VASSERT_EQ("string", "ab/cde/f", p.toString("/", vmime::charset("us-ascii")));
+ }
+
VMIME_TEST_SUITE_END