Moved POP3 response receiving and parsing to a separate class.
This commit is contained in:
parent
053d2b4ee0
commit
1ba5e8698c
@ -236,6 +236,7 @@ libvmime_messaging_proto_sources = [
|
||||
'net/pop3/POP3SStore.cpp', 'net/pop3/POP3SStore.hpp',
|
||||
'net/pop3/POP3Folder.cpp', 'net/pop3/POP3Folder.hpp',
|
||||
'net/pop3/POP3Message.cpp', 'net/pop3/POP3Message.hpp',
|
||||
'net/pop3/POP3Response.cpp', 'net/pop3/POP3Response.hpp',
|
||||
'net/pop3/POP3Utils.cpp', 'net/pop3/POP3Utils.hpp'
|
||||
]
|
||||
],
|
||||
|
@ -31,6 +31,7 @@
|
||||
|
||||
#include "vmime/net/pop3/POP3Store.hpp"
|
||||
#include "vmime/net/pop3/POP3Message.hpp"
|
||||
#include "vmime/net/pop3/POP3Response.hpp"
|
||||
|
||||
#include "vmime/net/pop3/POP3Utils.hpp"
|
||||
|
||||
@ -131,19 +132,17 @@ void POP3Folder::open(const int mode, bool failIfModeIsNotAvailable)
|
||||
{
|
||||
store->sendRequest("STAT");
|
||||
|
||||
string response;
|
||||
store->readResponse(response, false);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (!store->isSuccessResponse(response))
|
||||
throw exceptions::command_error("STAT", response);
|
||||
if (!response->isSuccess())
|
||||
throw exceptions::command_error("STAT", response->getFirstLine());
|
||||
|
||||
store->stripResponseCode(response, response);
|
||||
|
||||
std::istringstream iss(response);
|
||||
std::istringstream iss(response->getText());
|
||||
iss >> m_messageCount;
|
||||
|
||||
if (iss.fail())
|
||||
throw exceptions::invalid_response("STAT", response);
|
||||
throw exceptions::invalid_response("STAT", response->getFirstLine());
|
||||
|
||||
m_open = true;
|
||||
m_mode = mode;
|
||||
@ -167,9 +166,7 @@ void POP3Folder::close(const bool expunge)
|
||||
if (!expunge)
|
||||
{
|
||||
store->sendRequest("RSET");
|
||||
|
||||
string response;
|
||||
store->readResponse(response, false);
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
}
|
||||
|
||||
m_open = false;
|
||||
@ -371,13 +368,11 @@ void POP3Folder::fetchMessages(std::vector <ref <message> >& msg, const int opti
|
||||
store->sendRequest(command.str());
|
||||
|
||||
// Get the response
|
||||
string response;
|
||||
store->readResponse(response, true, NULL);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readMultilineResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (store->isSuccessResponse(response))
|
||||
if (response->isSuccess())
|
||||
{
|
||||
store->stripFirstLine(response, response, NULL);
|
||||
|
||||
// C: LIST
|
||||
// S: +OK
|
||||
// S: 1 47548
|
||||
@ -416,13 +411,11 @@ void POP3Folder::fetchMessages(std::vector <ref <message> >& msg, const int opti
|
||||
store->sendRequest(command.str());
|
||||
|
||||
// Get the response
|
||||
string response;
|
||||
store->readResponse(response, true, NULL);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readMultilineResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (store->isSuccessResponse(response))
|
||||
if (response->isSuccess())
|
||||
{
|
||||
store->stripFirstLine(response, response, NULL);
|
||||
|
||||
// C: UIDL
|
||||
// S: +OK
|
||||
// S: 1 whqtswO00WBw418f9t5JxYwZ
|
||||
@ -472,26 +465,26 @@ void POP3Folder::fetchMessage(ref <message> msg, const int options)
|
||||
store->sendRequest(command.str());
|
||||
|
||||
// Get the response
|
||||
string response;
|
||||
store->readResponse(response, false, NULL);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (store->isSuccessResponse(response))
|
||||
if (response->isSuccess())
|
||||
{
|
||||
store->stripResponseCode(response, response);
|
||||
string responseText = response->getText();
|
||||
|
||||
// C: LIST 2
|
||||
// S: +OK 2 4242
|
||||
string::iterator it = response.begin();
|
||||
string::iterator it = responseText.begin();
|
||||
|
||||
while (it != response.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != response.end() && !(*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != response.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
|
||||
if (it != response.end())
|
||||
if (it != responseText.end())
|
||||
{
|
||||
int size = 0;
|
||||
|
||||
std::istringstream iss(string(it, response.end()));
|
||||
std::istringstream iss(string(it, responseText.end()));
|
||||
iss >> size;
|
||||
|
||||
msg.dynamicCast <POP3Message>()->m_size = size;
|
||||
@ -510,25 +503,25 @@ void POP3Folder::fetchMessage(ref <message> msg, const int options)
|
||||
store->sendRequest(command.str());
|
||||
|
||||
// Get the response
|
||||
string response;
|
||||
store->readResponse(response, false, NULL);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (store->isSuccessResponse(response))
|
||||
if (response->isSuccess())
|
||||
{
|
||||
store->stripResponseCode(response, response);
|
||||
string responseText = response->getText();
|
||||
|
||||
// C: UIDL 2
|
||||
// S: +OK 2 QhdPYR:00WBw1Ph7x7
|
||||
string::iterator it = response.begin();
|
||||
string::iterator it = responseText.begin();
|
||||
|
||||
while (it != response.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != response.end() && !(*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != response.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it;
|
||||
while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
|
||||
|
||||
if (it != response.end())
|
||||
if (it != responseText.end())
|
||||
{
|
||||
msg.dynamicCast <POP3Message>()->m_uid =
|
||||
string(it, response.end());
|
||||
string(it, responseText.end());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -598,11 +591,11 @@ void POP3Folder::deleteMessage(const int num)
|
||||
|
||||
store->sendRequest(command.str());
|
||||
|
||||
string response;
|
||||
store->readResponse(response, false);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (!store->isSuccessResponse(response))
|
||||
throw exceptions::command_error("DELE", response);
|
||||
if (!response->isSuccess())
|
||||
throw exceptions::command_error("DELE", response->getFirstLine());
|
||||
|
||||
// Update local flags
|
||||
for (std::map <POP3Message*, int>::iterator it =
|
||||
@ -649,11 +642,11 @@ void POP3Folder::deleteMessages(const int from, const int to)
|
||||
|
||||
store->sendRequest(command.str());
|
||||
|
||||
string response;
|
||||
store->readResponse(response, false);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (!store->isSuccessResponse(response))
|
||||
throw exceptions::command_error("DELE", response);
|
||||
if (!response->isSuccess())
|
||||
throw exceptions::command_error("DELE", response->getFirstLine());
|
||||
}
|
||||
|
||||
// Update local flags
|
||||
@ -702,11 +695,11 @@ void POP3Folder::deleteMessages(const std::vector <int>& nums)
|
||||
|
||||
store->sendRequest(command.str());
|
||||
|
||||
string response;
|
||||
store->readResponse(response, false);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (!store->isSuccessResponse(response))
|
||||
throw exceptions::command_error("DELE", response);
|
||||
if (!response->isSuccess())
|
||||
throw exceptions::command_error("DELE", response->getFirstLine());
|
||||
}
|
||||
|
||||
// Sort message list
|
||||
@ -799,15 +792,13 @@ void POP3Folder::status(int& count, int& unseen)
|
||||
|
||||
store->sendRequest("STAT");
|
||||
|
||||
string response;
|
||||
store->readResponse(response, false);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(store->m_socket, store->m_timeoutHandler);
|
||||
|
||||
if (!store->isSuccessResponse(response))
|
||||
throw exceptions::command_error("STAT", response);
|
||||
if (!response->isSuccess())
|
||||
throw exceptions::command_error("STAT", response->getFirstLine());
|
||||
|
||||
store->stripResponseCode(response, response);
|
||||
|
||||
std::istringstream iss(response);
|
||||
std::istringstream iss(response->getText());
|
||||
iss >> count;
|
||||
|
||||
unseen = count;
|
||||
|
@ -28,10 +28,12 @@
|
||||
|
||||
|
||||
#include "vmime/net/pop3/POP3Message.hpp"
|
||||
#include "vmime/net/pop3/POP3Response.hpp"
|
||||
#include "vmime/net/pop3/POP3Folder.hpp"
|
||||
#include "vmime/net/pop3/POP3Store.hpp"
|
||||
|
||||
#include "vmime/utility/outputStreamAdapter.hpp"
|
||||
#include "vmime/utility/outputStreamStringAdapter.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@ -140,12 +142,14 @@ void POP3Message::extract(utility::outputStream& os,
|
||||
std::ostringstream oss;
|
||||
oss << "RETR " << m_num;
|
||||
|
||||
folder.constCast <POP3Folder>()->m_store.acquire()->sendRequest(oss.str());
|
||||
ref <POP3Store> store = folder.constCast <POP3Folder>()->m_store.acquire();
|
||||
|
||||
store->sendRequest(oss.str());
|
||||
|
||||
try
|
||||
{
|
||||
folder.constCast <POP3Folder>()->m_store.acquire()->
|
||||
readResponse(os, progress, m_size);
|
||||
POP3Response::readLargeResponse
|
||||
(store->m_socket, store->m_timeoutHandler, os, progress, m_size);
|
||||
}
|
||||
catch (exceptions::command_error& e)
|
||||
{
|
||||
@ -197,12 +201,17 @@ void POP3Message::fetch(ref <POP3Folder> msgFolder, const int options)
|
||||
std::ostringstream oss;
|
||||
oss << "TOP " << m_num << " 0";
|
||||
|
||||
folder->m_store.acquire()->sendRequest(oss.str());
|
||||
ref <POP3Store> store = folder->m_store.acquire();
|
||||
|
||||
store->sendRequest(oss.str());
|
||||
|
||||
try
|
||||
{
|
||||
string buffer;
|
||||
folder->m_store.acquire()->readResponse(buffer, true);
|
||||
utility::outputStreamStringAdapter bufferStream(buffer);
|
||||
|
||||
POP3Response::readLargeResponse(store->m_socket, store->m_timeoutHandler,
|
||||
bufferStream, /* progress */ NULL, /* predictedSize */ 0);
|
||||
|
||||
m_header = vmime::create <header>();
|
||||
m_header->parse(buffer);
|
||||
|
426
src/net/pop3/POP3Response.cpp
Normal file
426
src/net/pop3/POP3Response.cpp
Normal file
@ -0,0 +1,426 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2009 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 3 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/config.hpp"
|
||||
|
||||
|
||||
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
|
||||
|
||||
|
||||
#include "vmime/net/pop3/POP3Response.hpp"
|
||||
|
||||
#include "vmime/platform.hpp"
|
||||
|
||||
#include "vmime/utility/stringUtils.hpp"
|
||||
#include "vmime/utility/filteredStream.hpp"
|
||||
#include "vmime/utility/stringUtils.hpp"
|
||||
#include "vmime/utility/inputStreamSocketAdapter.hpp"
|
||||
|
||||
#include "vmime/net/socket.hpp"
|
||||
#include "vmime/net/timeoutHandler.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
namespace pop3 {
|
||||
|
||||
|
||||
POP3Response::POP3Response(ref <socket> sok, ref <timeoutHandler> toh)
|
||||
: m_socket(sok), m_timeoutHandler(toh)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
ref <POP3Response> POP3Response::readResponse
|
||||
(ref <socket> sok, ref <timeoutHandler> toh)
|
||||
{
|
||||
ref <POP3Response> resp = vmime::create <POP3Response>(sok, toh);
|
||||
|
||||
string buffer;
|
||||
resp->readResponseImpl(buffer, /* multiLine */ false);
|
||||
|
||||
resp->m_firstLine = buffer;
|
||||
resp->m_code = getResponseCode(buffer);
|
||||
stripResponseCode(buffer, resp->m_text);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
ref <POP3Response> POP3Response::readMultilineResponse
|
||||
(ref <socket> sok, ref <timeoutHandler> toh)
|
||||
{
|
||||
ref <POP3Response> resp = vmime::create <POP3Response>(sok, toh);
|
||||
|
||||
string buffer;
|
||||
resp->readResponseImpl(buffer, /* multiLine */ true);
|
||||
|
||||
string firstLine, nextLines;
|
||||
stripFirstLine(buffer, nextLines, &firstLine);
|
||||
|
||||
resp->m_firstLine = firstLine;
|
||||
resp->m_code = getResponseCode(firstLine);
|
||||
stripResponseCode(firstLine, resp->m_text);
|
||||
|
||||
std::istringstream iss(nextLines);
|
||||
string line;
|
||||
|
||||
while (std::getline(iss, line, '\n'))
|
||||
resp->m_lines.push_back(utility::stringUtils::trim(line));
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
ref <POP3Response> POP3Response::readLargeResponse
|
||||
(ref <socket> sok, ref <timeoutHandler> toh,
|
||||
utility::outputStream& os, utility::progressListener* progress, const long predictedSize)
|
||||
{
|
||||
ref <POP3Response> resp = vmime::create <POP3Response>(sok, toh);
|
||||
|
||||
string firstLine;
|
||||
resp->readResponseImpl(firstLine, os, progress, predictedSize);
|
||||
|
||||
resp->m_firstLine = firstLine;
|
||||
resp->m_code = getResponseCode(firstLine);
|
||||
stripResponseCode(firstLine, resp->m_text);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
bool POP3Response::isSuccess() const
|
||||
{
|
||||
return m_code == CODE_OK;
|
||||
}
|
||||
|
||||
|
||||
const string POP3Response::getFirstLine() const
|
||||
{
|
||||
return m_firstLine;
|
||||
}
|
||||
|
||||
|
||||
POP3Response::ResponseCode POP3Response::getCode() const
|
||||
{
|
||||
return m_code;
|
||||
}
|
||||
|
||||
|
||||
const string POP3Response::getText() const
|
||||
{
|
||||
return m_text;
|
||||
}
|
||||
|
||||
|
||||
const string POP3Response::getLineAt(const unsigned int pos) const
|
||||
{
|
||||
return m_lines[pos];
|
||||
}
|
||||
|
||||
|
||||
unsigned int POP3Response::getLineCount() const
|
||||
{
|
||||
return m_lines.size();
|
||||
}
|
||||
|
||||
|
||||
void POP3Response::readResponseImpl(string& buffer, const bool multiLine)
|
||||
{
|
||||
bool foundTerminator = false;
|
||||
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
buffer.clear();
|
||||
|
||||
string::value_type last1 = '\0', last2 = '\0';
|
||||
|
||||
for ( ; !foundTerminator ; )
|
||||
{
|
||||
// Check whether the time-out delay is elapsed
|
||||
if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
|
||||
{
|
||||
if (!m_timeoutHandler->handleTimeOut())
|
||||
throw exceptions::operation_timed_out();
|
||||
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
}
|
||||
|
||||
// Receive data from the socket
|
||||
string receiveBuffer;
|
||||
m_socket->receive(receiveBuffer);
|
||||
|
||||
if (receiveBuffer.empty()) // buffer is empty
|
||||
{
|
||||
platform::getHandler()->wait();
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have received data: reset the time-out counter
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
// Check for transparent characters: '\n..' becomes '\n.'
|
||||
const string::value_type first = receiveBuffer[0];
|
||||
|
||||
if (first == '.' && last2 == '\n' && last1 == '.')
|
||||
{
|
||||
receiveBuffer.erase(receiveBuffer.begin());
|
||||
}
|
||||
else if (receiveBuffer.length() >= 2 && first == '.' &&
|
||||
receiveBuffer[1] == '.' && last1 == '\n')
|
||||
{
|
||||
receiveBuffer.erase(receiveBuffer.begin());
|
||||
}
|
||||
|
||||
for (string::size_type trans ;
|
||||
string::npos != (trans = receiveBuffer.find("\n..")) ; )
|
||||
{
|
||||
receiveBuffer.replace(trans, 3, "\n.");
|
||||
}
|
||||
|
||||
last1 = receiveBuffer[receiveBuffer.length() - 1];
|
||||
last2 = static_cast <char>((receiveBuffer.length() >= 2) ? receiveBuffer[receiveBuffer.length() - 2] : 0);
|
||||
|
||||
// Append the data to the response buffer
|
||||
buffer += receiveBuffer;
|
||||
|
||||
// Check for terminator string (and strip it if present)
|
||||
foundTerminator = checkTerminator(buffer, multiLine);
|
||||
|
||||
// If there is an error (-ERR) when executing a command that
|
||||
// requires a multi-line response, the error response will
|
||||
// include only one line, so we stop waiting for a multi-line
|
||||
// terminator and check for a "normal" one.
|
||||
if (multiLine && !foundTerminator && buffer.length() >= 4 && buffer[0] == '-')
|
||||
{
|
||||
foundTerminator = checkTerminator(buffer, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void POP3Response::readResponseImpl
|
||||
(string& firstLine, utility::outputStream& os,
|
||||
utility::progressListener* progress, const long predictedSize)
|
||||
{
|
||||
long current = 0, total = predictedSize;
|
||||
|
||||
string temp;
|
||||
bool codeDone = false;
|
||||
|
||||
if (progress)
|
||||
progress->start(total);
|
||||
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
utility::inputStreamSocketAdapter sis(*m_socket);
|
||||
utility::stopSequenceFilteredInputStream <5> sfis1(sis, "\r\n.\r\n");
|
||||
utility::stopSequenceFilteredInputStream <3> sfis2(sfis1, "\n.\n");
|
||||
utility::dotFilteredInputStream dfis(sfis2); // "\n.." --> "\n."
|
||||
|
||||
utility::inputStream& is = dfis;
|
||||
|
||||
while (!is.eof())
|
||||
{
|
||||
#if 0 // not supported
|
||||
// Check for possible cancellation
|
||||
if (progress && progress->cancel())
|
||||
throw exceptions::operation_cancelled();
|
||||
#endif
|
||||
|
||||
// Check whether the time-out delay is elapsed
|
||||
if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
|
||||
{
|
||||
if (!m_timeoutHandler->handleTimeOut())
|
||||
throw exceptions::operation_timed_out();
|
||||
}
|
||||
|
||||
// Receive data from the socket
|
||||
utility::stream::value_type buffer[65536];
|
||||
const utility::stream::size_type read = is.read(buffer, sizeof(buffer));
|
||||
|
||||
if (read == 0) // buffer is empty
|
||||
{
|
||||
platform::getHandler()->wait();
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have received data: reset the time-out counter
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
// Notify progress
|
||||
current += read;
|
||||
|
||||
if (progress)
|
||||
{
|
||||
total = std::max(total, current);
|
||||
progress->progress(current, total);
|
||||
}
|
||||
|
||||
// If we don't have extracted the response code yet
|
||||
if (!codeDone)
|
||||
{
|
||||
temp.append(buffer, read);
|
||||
|
||||
string responseData;
|
||||
|
||||
if (stripFirstLine(temp, responseData, &firstLine) == true)
|
||||
{
|
||||
if (getResponseCode(firstLine) != CODE_OK)
|
||||
throw exceptions::command_error("?", firstLine);
|
||||
|
||||
codeDone = true;
|
||||
|
||||
os.write(responseData.data(), responseData.length());
|
||||
temp.clear();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inject the data into the output stream
|
||||
os.write(buffer, read);
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
progress->stop(total);
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool POP3Response::stripFirstLine
|
||||
(const string& buffer, string& result, string* firstLine)
|
||||
{
|
||||
const string::size_type end = buffer.find('\n');
|
||||
|
||||
if (end != string::npos)
|
||||
{
|
||||
if (firstLine) *firstLine = buffer.substr(0, end);
|
||||
result = buffer.substr(end + 1);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (firstLine) *firstLine = buffer;
|
||||
result = "";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
POP3Response::ResponseCode POP3Response::getResponseCode(const string& buffer)
|
||||
{
|
||||
if (buffer.length() >= 2)
|
||||
{
|
||||
// +[space]
|
||||
if (buffer[0] == '+' &&
|
||||
(buffer[1] == ' ' || buffer[1] == '\t'))
|
||||
{
|
||||
return CODE_READY;
|
||||
}
|
||||
|
||||
// +OK
|
||||
if (buffer.length() >= 3)
|
||||
{
|
||||
if (buffer[0] == '+' &&
|
||||
(buffer[1] == 'O' || buffer[1] == 'o') &&
|
||||
(buffer[2] == 'K' || buffer[1] == 'k'))
|
||||
{
|
||||
return CODE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -ERR or whatever
|
||||
return CODE_ERR;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
void POP3Response::stripResponseCode(const string& buffer, string& result)
|
||||
{
|
||||
const string::size_type pos = buffer.find_first_of(" \t");
|
||||
|
||||
if (pos != string::npos)
|
||||
result = buffer.substr(pos + 1);
|
||||
else
|
||||
result = buffer;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool POP3Response::checkTerminator(string& buffer, const bool multiLine)
|
||||
{
|
||||
// Multi-line response
|
||||
if (multiLine)
|
||||
{
|
||||
static const string term1("\r\n.\r\n");
|
||||
static const string term2("\n.\n");
|
||||
|
||||
return (checkOneTerminator(buffer, term1) ||
|
||||
checkOneTerminator(buffer, term2));
|
||||
}
|
||||
// Normal response
|
||||
else
|
||||
{
|
||||
static const string term1("\r\n");
|
||||
static const string term2("\n");
|
||||
|
||||
return (checkOneTerminator(buffer, term1) ||
|
||||
checkOneTerminator(buffer, term2));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// static
|
||||
bool POP3Response::checkOneTerminator(string& buffer, const string& term)
|
||||
{
|
||||
if (buffer.length() >= term.length() &&
|
||||
std::equal(buffer.end() - term.length(), buffer.end(), term.begin()))
|
||||
{
|
||||
buffer.erase(buffer.end() - term.length(), buffer.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // pop3
|
||||
} // net
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
|
@ -29,14 +29,12 @@
|
||||
|
||||
#include "vmime/net/pop3/POP3Store.hpp"
|
||||
#include "vmime/net/pop3/POP3Folder.hpp"
|
||||
#include "vmime/net/pop3/POP3Response.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/utility/inputStreamSocketAdapter.hpp"
|
||||
|
||||
#include "vmime/net/defaultConnectionInfos.hpp"
|
||||
|
||||
@ -174,13 +172,12 @@ void POP3Store::connect()
|
||||
// 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);
|
||||
ref <POP3Response> response = POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
if (!isSuccessResponse(response))
|
||||
if (!response->isSuccess())
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::connection_greeting_error(response);
|
||||
throw exceptions::connection_greeting_error(response->getFirstLine());
|
||||
}
|
||||
|
||||
#if VMIME_HAVE_TLS_SUPPORT
|
||||
@ -217,7 +214,7 @@ void POP3Store::connect()
|
||||
#endif // VMIME_HAVE_TLS_SUPPORT
|
||||
|
||||
// Start authentication process
|
||||
authenticate(messageId(response));
|
||||
authenticate(messageId(response->getText()));
|
||||
}
|
||||
|
||||
|
||||
@ -265,7 +262,7 @@ void POP3Store::authenticate(const messageId& randomMID)
|
||||
const string username = getAuthenticator()->getUsername();
|
||||
const string password = getAuthenticator()->getPassword();
|
||||
|
||||
string response;
|
||||
ref <POP3Response> response;
|
||||
|
||||
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP))
|
||||
{
|
||||
@ -280,9 +277,9 @@ void POP3Store::authenticate(const messageId& randomMID)
|
||||
md5->finalize();
|
||||
|
||||
sendRequest("APOP " + username + " " + md5->getHexDigest());
|
||||
readResponse(response, false);
|
||||
response = POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
if (isSuccessResponse(response))
|
||||
if (response->isSuccess())
|
||||
{
|
||||
m_authentified = true;
|
||||
return;
|
||||
@ -302,20 +299,19 @@ void POP3Store::authenticate(const messageId& randomMID)
|
||||
{
|
||||
// Can't fallback on basic authentication
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
throw exceptions::authentication_error(response->getFirstLine());
|
||||
}
|
||||
|
||||
// Ensure connection is valid (cf. note above)
|
||||
try
|
||||
{
|
||||
string response2;
|
||||
sendRequest("NOOP");
|
||||
readResponse(response2, false);
|
||||
POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
}
|
||||
catch (exceptions::socket_exception&)
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
throw exceptions::authentication_error(response->getFirstLine());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -339,21 +335,21 @@ void POP3Store::authenticate(const messageId& randomMID)
|
||||
// C: PASS couic
|
||||
// S: +OK vincent's maildrop has 2 messages (320 octets)
|
||||
sendRequest("USER " + username);
|
||||
readResponse(response, false);
|
||||
response = POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
if (!isSuccessResponse(response))
|
||||
if (!response->isSuccess())
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
throw exceptions::authentication_error(response->getFirstLine());
|
||||
}
|
||||
|
||||
sendRequest("PASS " + password);
|
||||
readResponse(response, false);
|
||||
response = POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
if (!isSuccessResponse(response))
|
||||
if (!response->isSuccess())
|
||||
{
|
||||
internalDisconnect();
|
||||
throw exceptions::authentication_error(response);
|
||||
throw exceptions::authentication_error(response->getFirstLine());
|
||||
}
|
||||
|
||||
m_authentified = true;
|
||||
@ -453,17 +449,16 @@ void POP3Store::authenticateSASL()
|
||||
|
||||
for (bool cont = true ; cont ; )
|
||||
{
|
||||
string response;
|
||||
readResponse(response, false);
|
||||
ref <POP3Response> response = POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
switch (getResponseCode(response))
|
||||
switch (response->getCode())
|
||||
{
|
||||
case RESPONSE_OK:
|
||||
case POP3Response::CODE_OK:
|
||||
{
|
||||
m_socket = saslSession->getSecuredSocket(m_socket);
|
||||
return;
|
||||
}
|
||||
case RESPONSE_READY:
|
||||
case POP3Response::CODE_READY:
|
||||
{
|
||||
byte_t* challenge = 0;
|
||||
long challengeLen = 0;
|
||||
@ -474,8 +469,7 @@ void POP3Store::authenticateSASL()
|
||||
try
|
||||
{
|
||||
// Extract challenge
|
||||
stripResponseCode(response, response);
|
||||
saslContext->decodeB64(response, &challenge, &challengeLen);
|
||||
saslContext->decodeB64(response->getText(), &challenge, &challengeLen);
|
||||
|
||||
// Prepare response
|
||||
saslSession->evaluateChallenge
|
||||
@ -543,11 +537,10 @@ void POP3Store::startTLS()
|
||||
{
|
||||
sendRequest("STLS");
|
||||
|
||||
string response;
|
||||
readResponse(response, false);
|
||||
ref <POP3Response> response = POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
if (getResponseCode(response) != RESPONSE_OK)
|
||||
throw exceptions::command_error("STLS", response);
|
||||
if (!response->isSuccess())
|
||||
throw exceptions::command_error("STLS", response->getFirstLine());
|
||||
|
||||
ref <tls::TLSSession> tlsSession =
|
||||
tls::TLSSession::create(getCertificateVerifier());
|
||||
@ -641,11 +634,11 @@ void POP3Store::noop()
|
||||
{
|
||||
sendRequest("NOOP");
|
||||
|
||||
string response;
|
||||
readResponse(response, false);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
if (!isSuccessResponse(response))
|
||||
throw exceptions::command_error("NOOP", response);
|
||||
if (!response->isSuccess())
|
||||
throw exceptions::command_error("NOOP", response->getFirstLine());
|
||||
}
|
||||
|
||||
|
||||
@ -653,89 +646,21 @@ const std::vector <string> POP3Store::getCapabilities()
|
||||
{
|
||||
sendRequest("CAPA");
|
||||
|
||||
string response;
|
||||
readResponse(response, true);
|
||||
ref <POP3Response> response =
|
||||
POP3Response::readMultilineResponse(m_socket, m_timeoutHandler);
|
||||
|
||||
std::vector <string> res;
|
||||
|
||||
if (isSuccessResponse(response))
|
||||
if (response->isSuccess())
|
||||
{
|
||||
stripFirstLine(response, response);
|
||||
|
||||
std::istringstream iss(response);
|
||||
string line;
|
||||
|
||||
while (std::getline(iss, line, '\n'))
|
||||
res.push_back(utility::stringUtils::trim(line));
|
||||
for (unsigned int i = 0, n = response->getLineCount() ; i < n ; ++i)
|
||||
res.push_back(response->getLineAt(i));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
bool POP3Store::isSuccessResponse(const string& buffer)
|
||||
{
|
||||
return getResponseCode(buffer) == RESPONSE_OK;
|
||||
}
|
||||
|
||||
|
||||
bool POP3Store::stripFirstLine(const string& buffer, string& result, string* firstLine)
|
||||
{
|
||||
const string::size_type end = buffer.find('\n');
|
||||
|
||||
if (end != string::npos)
|
||||
{
|
||||
if (firstLine) *firstLine = buffer.substr(0, end);
|
||||
result = buffer.substr(end + 1);
|
||||
return (true);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = buffer;
|
||||
return (false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int POP3Store::getResponseCode(const string& buffer)
|
||||
{
|
||||
if (buffer.length() >= 2)
|
||||
{
|
||||
// +[space]
|
||||
if (buffer[0] == '+' &&
|
||||
(buffer[1] == ' ' || buffer[1] == '\t'))
|
||||
{
|
||||
return RESPONSE_READY;
|
||||
}
|
||||
|
||||
// +OK
|
||||
if (buffer.length() >= 3)
|
||||
{
|
||||
if (buffer[0] == '+' &&
|
||||
(buffer[1] == 'O' || buffer[1] == 'o') &&
|
||||
(buffer[2] == 'K' || buffer[1] == 'k'))
|
||||
{
|
||||
return RESPONSE_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -ERR or whatever
|
||||
return RESPONSE_ERR;
|
||||
}
|
||||
|
||||
|
||||
void POP3Store::stripResponseCode(const string& buffer, string& result)
|
||||
{
|
||||
const string::size_type pos = buffer.find_first_of(" \t");
|
||||
|
||||
if (pos != string::npos)
|
||||
result = buffer.substr(pos + 1);
|
||||
else
|
||||
result = buffer;
|
||||
}
|
||||
|
||||
|
||||
void POP3Store::sendRequest(const string& buffer, const bool end)
|
||||
{
|
||||
if (end)
|
||||
@ -745,233 +670,6 @@ void POP3Store::sendRequest(const string& buffer, const bool end)
|
||||
}
|
||||
|
||||
|
||||
void POP3Store::readResponse(string& buffer, const bool multiLine,
|
||||
utility::progressListener* progress)
|
||||
{
|
||||
bool foundTerminator = false;
|
||||
long current = 0, total = 0;
|
||||
|
||||
if (progress)
|
||||
progress->start(total);
|
||||
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
buffer.clear();
|
||||
|
||||
string::value_type last1 = '\0', last2 = '\0';
|
||||
|
||||
for ( ; !foundTerminator ; )
|
||||
{
|
||||
#if 0 // not supported
|
||||
// Check for possible cancellation
|
||||
if (progress && progress->cancel())
|
||||
throw exceptions::operation_cancelled();
|
||||
#endif
|
||||
|
||||
// Check whether the time-out delay is elapsed
|
||||
if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
|
||||
{
|
||||
if (!m_timeoutHandler->handleTimeOut())
|
||||
throw exceptions::operation_timed_out();
|
||||
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
}
|
||||
|
||||
// Receive data from the socket
|
||||
string receiveBuffer;
|
||||
m_socket->receive(receiveBuffer);
|
||||
|
||||
if (receiveBuffer.empty()) // buffer is empty
|
||||
{
|
||||
platform::getHandler()->wait();
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have received data: reset the time-out counter
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
// Check for transparent characters: '\n..' becomes '\n.'
|
||||
const string::value_type first = receiveBuffer[0];
|
||||
|
||||
if (first == '.' && last2 == '\n' && last1 == '.')
|
||||
{
|
||||
receiveBuffer.erase(receiveBuffer.begin());
|
||||
}
|
||||
else if (receiveBuffer.length() >= 2 && first == '.' &&
|
||||
receiveBuffer[1] == '.' && last1 == '\n')
|
||||
{
|
||||
receiveBuffer.erase(receiveBuffer.begin());
|
||||
}
|
||||
|
||||
for (string::size_type trans ;
|
||||
string::npos != (trans = receiveBuffer.find("\n..")) ; )
|
||||
{
|
||||
receiveBuffer.replace(trans, 3, "\n.");
|
||||
}
|
||||
|
||||
last1 = receiveBuffer[receiveBuffer.length() - 1];
|
||||
last2 = static_cast <char>((receiveBuffer.length() >= 2) ? receiveBuffer[receiveBuffer.length() - 2] : 0);
|
||||
|
||||
// Append the data to the response buffer
|
||||
buffer += receiveBuffer;
|
||||
current += receiveBuffer.length();
|
||||
|
||||
// Check for terminator string (and strip it if present)
|
||||
foundTerminator = checkTerminator(buffer, multiLine);
|
||||
|
||||
// Notify progress
|
||||
if (progress)
|
||||
{
|
||||
total = std::max(total, current);
|
||||
progress->progress(current, total);
|
||||
}
|
||||
|
||||
// If there is an error (-ERR) when executing a command that
|
||||
// requires a multi-line response, the error response will
|
||||
// include only one line, so we stop waiting for a multi-line
|
||||
// terminator and check for a "normal" one.
|
||||
if (multiLine && !foundTerminator && buffer.length() >= 4 && buffer[0] == '-')
|
||||
{
|
||||
foundTerminator = checkTerminator(buffer, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
progress->stop(total);
|
||||
}
|
||||
|
||||
|
||||
void POP3Store::readResponse(utility::outputStream& os,
|
||||
utility::progressListener* progress, const int predictedSize)
|
||||
{
|
||||
long current = 0, total = predictedSize;
|
||||
|
||||
string temp;
|
||||
bool codeDone = false;
|
||||
|
||||
if (progress)
|
||||
progress->start(total);
|
||||
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
utility::inputStreamSocketAdapter sis(*m_socket);
|
||||
utility::stopSequenceFilteredInputStream <5> sfis1(sis, "\r\n.\r\n");
|
||||
utility::stopSequenceFilteredInputStream <3> sfis2(sfis1, "\n.\n");
|
||||
utility::dotFilteredInputStream dfis(sfis2); // "\n.." --> "\n."
|
||||
|
||||
utility::inputStream& is = dfis;
|
||||
|
||||
while (!is.eof())
|
||||
{
|
||||
#if 0 // not supported
|
||||
// Check for possible cancellation
|
||||
if (progress && progress->cancel())
|
||||
throw exceptions::operation_cancelled();
|
||||
#endif
|
||||
|
||||
// Check whether the time-out delay is elapsed
|
||||
if (m_timeoutHandler && m_timeoutHandler->isTimeOut())
|
||||
{
|
||||
if (!m_timeoutHandler->handleTimeOut())
|
||||
throw exceptions::operation_timed_out();
|
||||
}
|
||||
|
||||
// Receive data from the socket
|
||||
utility::stream::value_type buffer[65536];
|
||||
const utility::stream::size_type read = is.read(buffer, sizeof(buffer));
|
||||
|
||||
if (read == 0) // buffer is empty
|
||||
{
|
||||
platform::getHandler()->wait();
|
||||
continue;
|
||||
}
|
||||
|
||||
// We have received data: reset the time-out counter
|
||||
if (m_timeoutHandler)
|
||||
m_timeoutHandler->resetTimeOut();
|
||||
|
||||
// Notify progress
|
||||
current += read;
|
||||
|
||||
if (progress)
|
||||
{
|
||||
total = std::max(total, current);
|
||||
progress->progress(current, total);
|
||||
}
|
||||
|
||||
// If we don't have extracted the response code yet
|
||||
if (!codeDone)
|
||||
{
|
||||
temp.append(buffer, read);
|
||||
|
||||
string firstLine;
|
||||
|
||||
if (stripFirstLine(temp, temp, &firstLine) == true)
|
||||
{
|
||||
if (!isSuccessResponse(firstLine))
|
||||
throw exceptions::command_error("?", firstLine);
|
||||
|
||||
codeDone = true;
|
||||
|
||||
os.write(temp.data(), temp.length());
|
||||
temp.clear();
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Inject the data into the output stream
|
||||
os.write(buffer, read);
|
||||
}
|
||||
}
|
||||
|
||||
if (progress)
|
||||
progress->stop(total);
|
||||
}
|
||||
|
||||
|
||||
bool POP3Store::checkTerminator(string& buffer, const bool multiLine)
|
||||
{
|
||||
// Multi-line response
|
||||
if (multiLine)
|
||||
{
|
||||
static const string term1("\r\n.\r\n");
|
||||
static const string term2("\n.\n");
|
||||
|
||||
return (checkOneTerminator(buffer, term1) ||
|
||||
checkOneTerminator(buffer, term2));
|
||||
}
|
||||
// Normal response
|
||||
else
|
||||
{
|
||||
static const string term1("\r\n");
|
||||
static const string term2("\n");
|
||||
|
||||
return (checkOneTerminator(buffer, term1) ||
|
||||
checkOneTerminator(buffer, term2));
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
bool POP3Store::checkOneTerminator(string& buffer, const string& term)
|
||||
{
|
||||
if (buffer.length() >= term.length() &&
|
||||
std::equal(buffer.end() - term.length(), buffer.end(), term.begin()))
|
||||
{
|
||||
buffer.erase(buffer.end() - term.length(), buffer.end());
|
||||
return (true);
|
||||
}
|
||||
|
||||
return (false);
|
||||
}
|
||||
|
||||
|
||||
void POP3Store::registerFolder(POP3Folder* folder)
|
||||
{
|
||||
m_folders.push_back(folder);
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
|
||||
#include "vmime/net/pop3/POP3Utils.hpp"
|
||||
#include "vmime/net/pop3/POP3Response.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
@ -38,15 +39,13 @@ namespace pop3 {
|
||||
|
||||
|
||||
// static
|
||||
void POP3Utils::parseMultiListOrUidlResponse(const string& response, std::map <int, string>& result)
|
||||
void POP3Utils::parseMultiListOrUidlResponse(ref <POP3Response> response, std::map <int, string>& result)
|
||||
{
|
||||
std::istringstream iss(response);
|
||||
std::map <int, string> ids;
|
||||
|
||||
string line;
|
||||
|
||||
while (std::getline(iss, line))
|
||||
for (unsigned int i = 0, n = response->getLineCount() ; i < n ; ++i)
|
||||
{
|
||||
string line = response->getLineAt(i);
|
||||
string::iterator it = line.begin();
|
||||
|
||||
while (it != line.end() && (*it == ' ' || *it == '\t'))
|
||||
|
186
vmime/net/pop3/POP3Response.hpp
Normal file
186
vmime/net/pop3/POP3Response.hpp
Normal file
@ -0,0 +1,186 @@
|
||||
//
|
||||
// VMime library (http://www.vmime.org)
|
||||
// Copyright (C) 2002-2009 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 3 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.
|
||||
//
|
||||
|
||||
#ifndef VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
|
||||
#define VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
|
||||
|
||||
|
||||
#include "vmime/config.hpp"
|
||||
|
||||
|
||||
#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
|
||||
|
||||
|
||||
#include "vmime/object.hpp"
|
||||
#include "vmime/base.hpp"
|
||||
|
||||
#include "vmime/utility/outputStream.hpp"
|
||||
#include "vmime/utility/progressListener.hpp"
|
||||
|
||||
|
||||
namespace vmime {
|
||||
namespace net {
|
||||
|
||||
|
||||
class socket;
|
||||
class timeoutHandler;
|
||||
|
||||
|
||||
namespace pop3 {
|
||||
|
||||
|
||||
/** A POP3 response, as sent by the server.
|
||||
*/
|
||||
class POP3Response : public object
|
||||
{
|
||||
friend class vmime::creator;
|
||||
|
||||
public:
|
||||
|
||||
/** Possible response codes. */
|
||||
enum ResponseCode
|
||||
{
|
||||
CODE_OK = 0,
|
||||
CODE_READY,
|
||||
CODE_ERR
|
||||
};
|
||||
|
||||
|
||||
/** Receive and parse a POP3 response from the
|
||||
* specified socket.
|
||||
*
|
||||
* @param sok socket from which to read
|
||||
* @param toh time-out handler (can be NULL)
|
||||
* @return POP3 response
|
||||
* @throws exceptions::operation_timed_out if no data
|
||||
* has been received within the granted time
|
||||
*/
|
||||
static ref <POP3Response> readResponse
|
||||
(ref <socket> sok, ref <timeoutHandler> toh);
|
||||
|
||||
/** Receive and parse a multiline POP3 response from
|
||||
* the specified socket.
|
||||
*
|
||||
* @param sok socket from which to read
|
||||
* @param toh time-out handler (can be NULL)
|
||||
* @return POP3 response
|
||||
* @throws exceptions::operation_timed_out if no data
|
||||
* has been received within the granted time
|
||||
*/
|
||||
static ref <POP3Response> readMultilineResponse
|
||||
(ref <socket> sok, ref <timeoutHandler> toh);
|
||||
|
||||
/** Receive and parse a large POP3 response (eg. message data)
|
||||
* from the specified socket.
|
||||
*
|
||||
* @param sok socket from which to read
|
||||
* @param toh time-out handler (can be NULL)
|
||||
* @param os output stream to which response data will be written
|
||||
* @param progress progress listener (can be NULL)
|
||||
* @param predictedSize estimated size of response data (in bytes)
|
||||
* @return POP3 response
|
||||
* @throws exceptions::operation_timed_out if no data
|
||||
* has been received within the granted time
|
||||
*/
|
||||
static ref <POP3Response> readLargeResponse
|
||||
(ref <socket> sok, ref <timeoutHandler> toh,
|
||||
utility::outputStream& os,
|
||||
utility::progressListener* progress, const long predictedSize);
|
||||
|
||||
|
||||
/** Returns whether the response is successful ("OK").
|
||||
*
|
||||
* @return true if the response if successful, false otherwise
|
||||
*/
|
||||
bool isSuccess() const;
|
||||
|
||||
/** Return the POP3 response code.
|
||||
*
|
||||
* @return response code
|
||||
*/
|
||||
ResponseCode getCode() const;
|
||||
|
||||
/** Return the POP3 response text (first line).
|
||||
*
|
||||
* @return response text
|
||||
*/
|
||||
const string getText() const;
|
||||
|
||||
/** Return the first POP3 response line.
|
||||
*
|
||||
* @return first response line
|
||||
*/
|
||||
const string getFirstLine() const;
|
||||
|
||||
/** Return the response line at the specified position.
|
||||
*
|
||||
* @param pos line index
|
||||
* @return line at the specified index
|
||||
*/
|
||||
const string getLineAt(const unsigned int pos) const;
|
||||
|
||||
/** Return the number of lines in the response.
|
||||
*
|
||||
* @return number of lines in the response
|
||||
*/
|
||||
unsigned int getLineCount() const;
|
||||
|
||||
private:
|
||||
|
||||
POP3Response(ref <socket> sok, ref <timeoutHandler> toh);
|
||||
|
||||
void readResponseImpl(string& buffer, const bool multiLine);
|
||||
void readResponseImpl
|
||||
(string& firstLine, utility::outputStream& os,
|
||||
utility::progressListener* progress, const long predictedSize);
|
||||
|
||||
|
||||
static bool stripFirstLine(const string& buffer, string& result, string* firstLine);
|
||||
|
||||
static ResponseCode getResponseCode(const string& buffer);
|
||||
|
||||
static void stripResponseCode(const string& buffer, string& result);
|
||||
|
||||
static bool checkTerminator(string& buffer, const bool multiLine);
|
||||
static bool checkOneTerminator(string& buffer, const string& term);
|
||||
|
||||
|
||||
ref <socket> m_socket;
|
||||
ref <timeoutHandler> m_timeoutHandler;
|
||||
|
||||
string m_firstLine;
|
||||
ResponseCode m_code;
|
||||
string m_text;
|
||||
|
||||
std::vector <string> m_lines;
|
||||
};
|
||||
|
||||
|
||||
} // pop3
|
||||
} // net
|
||||
} // vmime
|
||||
|
||||
|
||||
#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
|
||||
|
||||
#endif // VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
|
@ -87,13 +87,6 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
enum ResponseCode
|
||||
{
|
||||
RESPONSE_OK = 0,
|
||||
RESPONSE_READY,
|
||||
RESPONSE_ERR
|
||||
};
|
||||
|
||||
void authenticate(const messageId& randomMID);
|
||||
#if VMIME_HAVE_SASL_SUPPORT
|
||||
void authenticateSASL();
|
||||
@ -105,17 +98,7 @@ private:
|
||||
|
||||
const std::vector <string> getCapabilities();
|
||||
|
||||
static bool isSuccessResponse(const string& buffer);
|
||||
static bool stripFirstLine(const string& buffer, string& result, string* firstLine = NULL);
|
||||
static void stripResponseCode(const string& buffer, string& result);
|
||||
static int getResponseCode(const string& buffer);
|
||||
|
||||
void sendRequest(const string& buffer, const bool end = true);
|
||||
void readResponse(string& buffer, const bool multiLine, utility::progressListener* progress = NULL);
|
||||
void readResponse(utility::outputStream& os, utility::progressListener* progress = NULL, const int predictedSize = 0);
|
||||
|
||||
static bool checkTerminator(string& buffer, const bool multiLine);
|
||||
static bool checkOneTerminator(string& buffer, const string& term);
|
||||
|
||||
void internalDisconnect();
|
||||
|
||||
|
@ -41,6 +41,9 @@ namespace net {
|
||||
namespace pop3 {
|
||||
|
||||
|
||||
class POP3Response;
|
||||
|
||||
|
||||
class POP3Utils
|
||||
{
|
||||
public:
|
||||
@ -59,7 +62,7 @@ public:
|
||||
* data (either UID or size)
|
||||
*/
|
||||
static void parseMultiListOrUidlResponse
|
||||
(const string& response, std::map <int, string>& result);
|
||||
(ref <POP3Response> response, std::map <int, string>& result);
|
||||
};
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user