Renamed 'vmime::messaging' to 'vmime::net'.

This commit is contained in:
Vincent Richard 2005-08-23 19:11:19 +00:00
parent 8cdddcdf03
commit 28bafee944
81 changed files with 19019 additions and 171 deletions

View File

@ -2,6 +2,12 @@
VERSION 0.7.2cvs VERSION 0.7.2cvs
================ ================
2005-08-23 Vincent Richard <vincent@vincent-richard.net>
* All sources: renamed 'vmime::messaging' to 'vmime::net'. An alias has been
kept for compatibility with previous versions (its use should be considered
as deprecated).
2005-08-19 Vincent Richard <vincent@vincent-richard.net> 2005-08-19 Vincent Richard <vincent@vincent-richard.net>
* exception.hpp: vmime::exception now inherits from std::exception. * exception.hpp: vmime::exception now inherits from std::exception.

View File

@ -58,7 +58,7 @@ packageAPIAge = packageVersionMinor
packageName = 'libvmime' packageName = 'libvmime'
packageGenericName = 'vmime' packageGenericName = 'vmime'
packageRealName = 'VMime Library' packageRealName = 'VMime Library'
packageDescription = 'VMime C++ Mail Library (http://vmime.sourceforge.net)' packageDescription = 'VMime C++ Mail Library (http://www.vmime.org)'
packageMaintainer = 'vincent@vincent-richard.net' packageMaintainer = 'vincent@vincent-richard.net'
packageVersion = '%d.%d.%d' % (packageVersionMajor, packageVersionMinor, packageVersionMicro) packageVersion = '%d.%d.%d' % (packageVersionMajor, packageVersionMinor, packageVersionMicro)
@ -182,65 +182,65 @@ libvmime_examples_sources = [
] ]
libvmime_messaging_sources = [ libvmime_messaging_sources = [
'messaging/authenticator.cpp', 'messaging/authenticator.hpp', 'net/authenticator.cpp', 'net/authenticator.hpp',
'messaging/authenticationInfos.cpp', 'messaging/authenticationInfos.hpp', 'net/authenticationInfos.cpp', 'net/authenticationInfos.hpp',
'messaging/authHelper.cpp', 'messaging/authHelper.hpp', 'net/authHelper.cpp', 'net/authHelper.hpp',
'messaging/builtinServices.inl', 'net/builtinServices.inl',
'messaging/defaultAuthenticator.cpp', 'messaging/defaultAuthenticator.hpp', 'net/defaultAuthenticator.cpp', 'net/defaultAuthenticator.hpp',
'messaging/events.cpp', 'messaging/events.hpp', 'net/events.cpp', 'net/events.hpp',
'messaging/folder.cpp', 'messaging/folder.hpp', 'net/folder.cpp', 'net/folder.hpp',
'messaging/message.cpp', 'messaging/message.hpp', 'net/message.cpp', 'net/message.hpp',
'messaging/service.cpp', 'messaging/service.hpp', 'net/service.cpp', 'net/service.hpp',
'messaging/serviceFactory.cpp', 'messaging/serviceFactory.hpp', 'net/serviceFactory.cpp', 'net/serviceFactory.hpp',
'messaging/serviceInfos.cpp', 'messaging/serviceInfos.hpp', 'net/serviceInfos.cpp', 'net/serviceInfos.hpp',
'messaging/session.cpp', 'messaging/session.hpp', 'net/session.cpp', 'net/session.hpp',
'messaging/simpleAuthenticator.cpp', 'messaging/simpleAuthenticator.hpp', 'net/simpleAuthenticator.cpp', 'net/simpleAuthenticator.hpp',
'messaging/socket.hpp', 'net/socket.hpp',
'messaging/store.hpp', 'net/store.hpp',
'messaging/timeoutHandler.hpp', 'net/timeoutHandler.hpp',
'messaging/transport.cpp', 'messaging/transport.hpp' 'net/transport.cpp', 'net/transport.hpp'
] ]
libvmime_messaging_proto_sources = [ libvmime_messaging_proto_sources = [
[ [
'pop3', 'pop3',
[ [
'messaging/pop3/POP3Store.cpp', 'messaging/pop3/POP3Store.hpp', 'net/pop3/POP3Store.cpp', 'net/pop3/POP3Store.hpp',
'messaging/pop3/POP3Folder.cpp', 'messaging/pop3/POP3Folder.hpp', 'net/pop3/POP3Folder.cpp', 'net/pop3/POP3Folder.hpp',
'messaging/pop3/POP3Message.cpp', 'messaging/pop3/POP3Message.hpp' 'net/pop3/POP3Message.cpp', 'net/pop3/POP3Message.hpp'
] ]
], ],
[ [
'smtp', 'smtp',
[ [
'messaging/smtp/SMTPTransport.cpp', 'messaging/smtp/SMTPTransport.hpp' 'net/smtp/SMTPTransport.cpp', 'net/smtp/SMTPTransport.hpp'
] ]
], ],
[ [
'imap', 'imap',
[ [
'messaging/imap/IMAPConnection.cpp', 'messaging/imap/IMAPConnection.hpp', 'net/imap/IMAPConnection.cpp', 'net/imap/IMAPConnection.hpp',
'messaging/imap/IMAPStore.cpp', 'messaging/imap/IMAPStore.hpp', 'net/imap/IMAPStore.cpp', 'net/imap/IMAPStore.hpp',
'messaging/imap/IMAPFolder.cpp', 'messaging/imap/IMAPFolder.hpp', 'net/imap/IMAPFolder.cpp', 'net/imap/IMAPFolder.hpp',
'messaging/imap/IMAPMessage.cpp', 'messaging/imap/IMAPMessage.hpp', 'net/imap/IMAPMessage.cpp', 'net/imap/IMAPMessage.hpp',
'messaging/imap/IMAPTag.cpp', 'messaging/imap/IMAPTag.hpp', 'net/imap/IMAPTag.cpp', 'net/imap/IMAPTag.hpp',
'messaging/imap/IMAPUtils.cpp', 'messaging/imap/IMAPUtils.hpp', 'net/imap/IMAPUtils.cpp', 'net/imap/IMAPUtils.hpp',
'messaging/imap/IMAPParser.hpp' 'net/imap/IMAPParser.hpp'
] ]
], ],
[ [
'maildir', 'maildir',
[ [
'messaging/maildir/maildirStore.cpp', 'messaging/maildir/maildirStore.hpp', 'net/maildir/maildirStore.cpp', 'net/maildir/maildirStore.hpp',
'messaging/maildir/maildirFolder.cpp', 'messaging/maildir/maildirFolder.hpp', 'net/maildir/maildirFolder.cpp', 'net/maildir/maildirFolder.hpp',
'messaging/maildir/maildirMessage.cpp', 'messaging/maildir/maildirMessage.hpp', 'net/maildir/maildirMessage.cpp', 'net/maildir/maildirMessage.hpp',
'messaging/maildir/maildirUtils.cpp', 'messaging/maildir/maildirUtils.hpp' 'net/maildir/maildirUtils.cpp', 'net/maildir/maildirUtils.hpp'
] ]
], ],
[ [
'sendmail', 'sendmail',
[ [
'messaging/sendmail/sendmailTransport.cpp', 'messaging/sendmail/sendmailTransport.hpp' 'net/sendmail/sendmailTransport.cpp', 'net/sendmail/sendmailTransport.hpp'
] ]
] ]
] ]

View File

@ -26,14 +26,14 @@
// Global session object // Global session object
static vmime::ref <vmime::messaging::session> g_session static vmime::ref <vmime::net::session> g_session
= vmime::create <vmime::messaging::session>(); = vmime::create <vmime::net::session>();
// Authentification handler // Authentification handler
class interactiveAuthenticator : public vmime::messaging::authenticator class interactiveAuthenticator : public vmime::net::authenticator
{ {
const vmime::messaging::authenticationInfos requestAuthInfos() const const vmime::net::authenticationInfos requestAuthInfos() const
{ {
vmime::string username, password; vmime::string username, password;
@ -50,7 +50,7 @@ class interactiveAuthenticator : public vmime::messaging::authenticator
std::getline(std::cin, password); std::getline(std::cin, password);
return (vmime::messaging::authenticationInfos(username, password)); return (vmime::net::authenticationInfos(username, password));
} }
}; };
@ -108,11 +108,11 @@ static std::ostream& operator<<(std::ostream& os, const vmime::exception& e)
* @param s structure object * @param s structure object
* @param level current depth * @param level current depth
*/ */
static void printStructure(const vmime::messaging::structure& s, const int level = 0) static void printStructure(const vmime::net::structure& s, const int level = 0)
{ {
for (int i = 1 ; i <= s.getCount() ; ++i) for (int i = 1 ; i <= s.getCount() ; ++i)
{ {
const vmime::messaging::part& part = s[i]; const vmime::net::part& part = s[i];
for (int j = 0 ; j < level * 2 ; ++j) for (int j = 0 ; j < level * 2 ; ++j)
std::cout << " "; std::cout << " ";
@ -127,7 +127,7 @@ static void printStructure(const vmime::messaging::structure& s, const int level
} }
static const vmime::string getFolderPathString(vmime::ref <vmime::messaging::folder> f) static const vmime::string getFolderPathString(vmime::ref <vmime::net::folder> f)
{ {
const vmime::string n = f->getName().getBuffer(); const vmime::string n = f->getName().getBuffer();
@ -137,7 +137,7 @@ static const vmime::string getFolderPathString(vmime::ref <vmime::messaging::fol
} }
else else
{ {
vmime::ref <vmime::messaging::folder> p = f->getParent(); vmime::ref <vmime::net::folder> p = f->getParent();
return getFolderPathString(p) + n + "/"; return getFolderPathString(p) + n + "/";
} }
} }
@ -147,14 +147,14 @@ static const vmime::string getFolderPathString(vmime::ref <vmime::messaging::fol
* *
* @param folder current folder * @param folder current folder
*/ */
static void printFolders(vmime::ref <vmime::messaging::folder> folder, const int level = 0) static void printFolders(vmime::ref <vmime::net::folder> folder, const int level = 0)
{ {
for (int j = 0 ; j < level * 2 ; ++j) for (int j = 0 ; j < level * 2 ; ++j)
std::cout << " "; std::cout << " ";
std::cout << getFolderPathString(folder) << std::endl; std::cout << getFolderPathString(folder) << std::endl;
std::vector <vmime::ref <vmime::messaging::folder> > subFolders = folder->getFolders(false); std::vector <vmime::ref <vmime::net::folder> > subFolders = folder->getFolders(false);
for (unsigned int i = 0 ; i < subFolders.size() ; ++i) for (unsigned int i = 0 ; i < subFolders.size() ; ++i)
printFolders(subFolders[i], level + 1); printFolders(subFolders[i], level + 1);
@ -210,7 +210,7 @@ static void sendMessage()
vmime::utility::url url(urlString); vmime::utility::url url(urlString);
vmime::ref <vmime::messaging::transport> tr = vmime::ref <vmime::net::transport> tr =
g_session->getTransport(url, vmime::create <interactiveAuthenticator>()); g_session->getTransport(url, vmime::create <interactiveAuthenticator>());
// You can also set some properties (see example7 to know the properties // You can also set some properties (see example7 to know the properties
@ -307,7 +307,7 @@ static void connectStore()
// If no authenticator is given in argument to getStore(), a default one // If no authenticator is given in argument to getStore(), a default one
// is used. Its behaviour is to get the user credentials from the // is used. Its behaviour is to get the user credentials from the
// session properties "auth.username" and "auth.password". // session properties "auth.username" and "auth.password".
vmime::ref <vmime::messaging::store> st; vmime::ref <vmime::net::store> st;
if (url.getUsername().empty() || url.getPassword().empty()) if (url.getUsername().empty() || url.getPassword().empty())
st = g_session->getStore(url, vmime::create <interactiveAuthenticator>()); st = g_session->getStore(url, vmime::create <interactiveAuthenticator>());
@ -318,10 +318,10 @@ static void connectStore()
st->connect(); st->connect();
// Open the default folder in this store // Open the default folder in this store
vmime::ref <vmime::messaging::folder> f = st->getDefaultFolder(); vmime::ref <vmime::net::folder> f = st->getDefaultFolder();
// vmime::ref <vmime::messaging::folder> f = st->getFolder(vmime::utility::path("a")); // vmime::ref <vmime::net::folder> f = st->getFolder(vmime::utility::path("a"));
f->open(vmime::messaging::folder::MODE_READ_WRITE); f->open(vmime::net::folder::MODE_READ_WRITE);
int count = f->getMessageCount(); int count = f->getMessageCount();
@ -330,7 +330,7 @@ static void connectStore()
for (bool cont = true ; cont ; ) for (bool cont = true ; cont ; )
{ {
typedef std::map <int, vmime::ref <vmime::messaging::message> > MessageList; typedef std::map <int, vmime::ref <vmime::net::message> > MessageList;
MessageList msgList; MessageList msgList;
try try
@ -348,7 +348,7 @@ static void connectStore()
const int choice = printMenu(choices); const int choice = printMenu(choices);
// Request message number // Request message number
vmime::ref <vmime::messaging::message> msg; vmime::ref <vmime::net::message> msg;
if (choice != 6 && choice != 7) if (choice != 6 && choice != 7)
{ {
@ -389,19 +389,19 @@ static void connectStore()
// Show message flags // Show message flags
case 1: case 1:
f->fetchMessage(msg, vmime::messaging::folder::FETCH_FLAGS); f->fetchMessage(msg, vmime::net::folder::FETCH_FLAGS);
if (msg->getFlags() & vmime::messaging::message::FLAG_SEEN) if (msg->getFlags() & vmime::net::message::FLAG_SEEN)
std::cout << "FLAG_SEEN" << std::endl; std::cout << "FLAG_SEEN" << std::endl;
if (msg->getFlags() & vmime::messaging::message::FLAG_RECENT) if (msg->getFlags() & vmime::net::message::FLAG_RECENT)
std::cout << "FLAG_RECENT" << std::endl; std::cout << "FLAG_RECENT" << std::endl;
if (msg->getFlags() & vmime::messaging::message::FLAG_REPLIED) if (msg->getFlags() & vmime::net::message::FLAG_REPLIED)
std::cout << "FLAG_REPLIED" << std::endl; std::cout << "FLAG_REPLIED" << std::endl;
if (msg->getFlags() & vmime::messaging::message::FLAG_DELETED) if (msg->getFlags() & vmime::net::message::FLAG_DELETED)
std::cout << "FLAG_DELETED" << std::endl; std::cout << "FLAG_DELETED" << std::endl;
if (msg->getFlags() & vmime::messaging::message::FLAG_MARKED) if (msg->getFlags() & vmime::net::message::FLAG_MARKED)
std::cout << "FLAG_MARKED" << std::endl; std::cout << "FLAG_MARKED" << std::endl;
if (msg->getFlags() & vmime::messaging::message::FLAG_PASSED) if (msg->getFlags() & vmime::net::message::FLAG_PASSED)
std::cout << "FLAG_PASSED" << std::endl; std::cout << "FLAG_PASSED" << std::endl;
break; break;
@ -409,21 +409,21 @@ static void connectStore()
// Show message structure // Show message structure
case 2: case 2:
f->fetchMessage(msg, vmime::messaging::folder::FETCH_STRUCTURE); f->fetchMessage(msg, vmime::net::folder::FETCH_STRUCTURE);
printStructure(msg->getStructure()); printStructure(msg->getStructure());
break; break;
// Show message header // Show message header
case 3: case 3:
f->fetchMessage(msg, vmime::messaging::folder::FETCH_FULL_HEADER); f->fetchMessage(msg, vmime::net::folder::FETCH_FULL_HEADER);
std::cout << msg->getHeader()->generate() << std::endl; std::cout << msg->getHeader()->generate() << std::endl;
break; break;
// Show message envelope // Show message envelope
case 4: case 4:
f->fetchMessage(msg, vmime::messaging::folder::FETCH_ENVELOPE); f->fetchMessage(msg, vmime::net::folder::FETCH_ENVELOPE);
#define ENV_HELPER(x) \ #define ENV_HELPER(x) \
try { std::cout << msg->getHeader()->x()->generate() << std::endl; } \ try { std::cout << msg->getHeader()->x()->generate() << std::endl; } \
@ -449,7 +449,7 @@ static void connectStore()
// List folders // List folders
case 6: case 6:
{ {
vmime::ref <vmime::messaging::folder> vmime::ref <vmime::net::folder>
root = st->getRootFolder(); root = st->getRootFolder();
printFolders(root); printFolders(root);
@ -477,19 +477,19 @@ static void connectStore()
// Folder renaming // Folder renaming
{ {
vmime::ref <vmime::messaging::folder> f = st->getFolder(vmime::messaging::folder::path("c")); vmime::ref <vmime::net::folder> f = st->getFolder(vmime::net::folder::path("c"));
f->rename(vmime::messaging::folder::path("c2")); f->rename(vmime::net::folder::path("c2"));
vmime::ref <vmime::messaging::folder> g = st->getFolder(vmime::messaging::folder::path("c2")); vmime::ref <vmime::net::folder> g = st->getFolder(vmime::net::folder::path("c2"));
g->rename(vmime::messaging::folder::path("c")); g->rename(vmime::net::folder::path("c"));
} }
// Message copy: copy all messages from 'f' to 'g' // Message copy: copy all messages from 'f' to 'g'
{ {
vmime::ref <vmime::messaging::folder> g = st->getFolder(vmime::messaging::folder::path("TEMP")); vmime::ref <vmime::net::folder> g = st->getFolder(vmime::net::folder::path("TEMP"));
if (!g->exists()) if (!g->exists())
g->create(vmime::messaging::folder::TYPE_CONTAINS_MESSAGES); g->create(vmime::net::folder::TYPE_CONTAINS_MESSAGES);
f->copyMessages(g->getFullPath()); f->copyMessages(g->getFullPath());
} }

View File

@ -60,23 +60,23 @@ int main()
std::cout << std::endl; std::cout << std::endl;
// Enumerate messaging services and their properties // Enumerate messaging services and their properties
vmime::messaging::serviceFactory* sf = vmime::messaging::serviceFactory::getInstance(); vmime::net::serviceFactory* sf = vmime::net::serviceFactory::getInstance();
std::cout << "Available messaging services:" << std::endl; std::cout << "Available messaging services:" << std::endl;
for (int i = 0 ; i < sf->getServiceCount() ; ++i) for (int i = 0 ; i < sf->getServiceCount() ; ++i)
{ {
const vmime::messaging::serviceFactory::registeredService& serv = *sf->getServiceAt(i); const vmime::net::serviceFactory::registeredService& serv = *sf->getServiceAt(i);
std::cout << " * " << serv.getName() << std::endl; std::cout << " * " << serv.getName() << std::endl;
std::vector <vmime::messaging::serviceInfos::property> props = std::vector <vmime::net::serviceInfos::property> props =
serv.getInfos().getAvailableProperties(); serv.getInfos().getAvailableProperties();
for (std::vector <vmime::messaging::serviceInfos::property>::const_iterator it = props.begin() ; for (std::vector <vmime::net::serviceInfos::property>::const_iterator it = props.begin() ;
it != props.end() ; ++it) it != props.end() ; ++it)
{ {
const vmime::messaging::serviceInfos::property& p = *it; const vmime::net::serviceInfos::property& p = *it;
const vmime::string name = serv.getInfos().getPropertyPrefix() + p.getName(); const vmime::string name = serv.getInfos().getPropertyPrefix() + p.getName();
@ -84,17 +84,17 @@ int main()
switch (p.getType()) switch (p.getType())
{ {
case vmime::messaging::serviceInfos::property::TYPE_INTEGER: type = "TYPE_INTEGER"; break; case vmime::net::serviceInfos::property::TYPE_INTEGER: type = "TYPE_INTEGER"; break;
case vmime::messaging::serviceInfos::property::TYPE_STRING: type = "TYPE_STRING"; break; case vmime::net::serviceInfos::property::TYPE_STRING: type = "TYPE_STRING"; break;
case vmime::messaging::serviceInfos::property::TYPE_BOOL: type = "TYPE_BOOL"; break; case vmime::net::serviceInfos::property::TYPE_BOOL: type = "TYPE_BOOL"; break;
default: type = "(unknown)"; break; default: type = "(unknown)"; break;
} }
vmime::string flags; vmime::string flags;
if (p.getFlags() & vmime::messaging::serviceInfos::property::FLAG_REQUIRED) if (p.getFlags() & vmime::net::serviceInfos::property::FLAG_REQUIRED)
flags += " FLAG_REQUIRED"; flags += " FLAG_REQUIRED";
if (p.getFlags() & vmime::messaging::serviceInfos::property::FLAG_HIDDEN) if (p.getFlags() & vmime::net::serviceInfos::property::FLAG_HIDDEN)
flags += " FLAG_HIDDEN"; flags += " FLAG_HIDDEN";
std::cout << " - " << serv.getInfos().getPropertyPrefix() + p.getName(); std::cout << " - " << serv.getInfos().getPropertyPrefix() + p.getName();

View File

@ -40,7 +40,7 @@
#include "vmime/options.hpp" #include "vmime/options.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
#include "vmime/messaging/serviceFactory.hpp" #include "vmime/net/serviceFactory.hpp"
#endif #endif
@ -143,7 +143,7 @@ public:
textPartFactory::getInstance(); textPartFactory::getInstance();
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
messaging::serviceFactory::getInstance(); net::serviceFactory::getInstance();
#endif #endif
} }
}; };

View File

@ -317,15 +317,15 @@ const char* system_error::name() const throw() { return "system_error"; }
// //
// messaging_exception // net_exception
// //
messaging_exception::~messaging_exception() throw() {} net_exception::~net_exception() throw() {}
messaging_exception::messaging_exception(const string& what, const exception& other) net_exception::net_exception(const string& what, const exception& other)
: exception(what, other) {} : exception(what, other) {}
exception* messaging_exception::clone() const { return new messaging_exception(*this); } exception* net_exception::clone() const { return new net_exception(*this); }
const char* messaging_exception::name() const throw() { return "messaging_exception"; } const char* net_exception::name() const throw() { return "net_exception"; }
// //
@ -334,7 +334,7 @@ const char* messaging_exception::name() const throw() { return "messaging_except
connection_error::~connection_error() throw() {} connection_error::~connection_error() throw() {}
connection_error::connection_error(const string& what, const exception& other) connection_error::connection_error(const string& what, const exception& other)
: messaging_exception(what.empty() : net_exception(what.empty()
? "Connection error." ? "Connection error."
: "Connection error: '" + what + "'.", other) {} : "Connection error: '" + what + "'.", other) {}
@ -348,7 +348,7 @@ const char* connection_error::name() const throw() { return "connection_error";
connection_greeting_error::~connection_greeting_error() throw() {} connection_greeting_error::~connection_greeting_error() throw() {}
connection_greeting_error::connection_greeting_error(const string& response, const exception& other) connection_greeting_error::connection_greeting_error(const string& response, const exception& other)
: messaging_exception("Greeting error.", other), m_response(response) {} : net_exception("Greeting error.", other), m_response(response) {}
const string& connection_greeting_error::response() const { return (m_response); } const string& connection_greeting_error::response() const { return (m_response); }
@ -362,7 +362,7 @@ const char* connection_greeting_error::name() const throw() { return "connection
authentication_error::~authentication_error() throw() {} authentication_error::~authentication_error() throw() {}
authentication_error::authentication_error(const string& response, const exception& other) authentication_error::authentication_error(const string& response, const exception& other)
: messaging_exception("Authentication error.", other), m_response(response) {} : net_exception("Authentication error.", other), m_response(response) {}
const string& authentication_error::response() const { return (m_response); } const string& authentication_error::response() const { return (m_response); }
@ -376,7 +376,7 @@ const char* authentication_error::name() const throw() { return "authentication_
unsupported_option::~unsupported_option() throw() {} unsupported_option::~unsupported_option() throw() {}
unsupported_option::unsupported_option(const exception& other) unsupported_option::unsupported_option(const exception& other)
: messaging_exception("Unsupported option.", other) {} : net_exception("Unsupported option.", other) {}
exception* unsupported_option::clone() const { return new unsupported_option(*this); } exception* unsupported_option::clone() const { return new unsupported_option(*this); }
const char* unsupported_option::name() const throw() { return "unsupported_option"; } const char* unsupported_option::name() const throw() { return "unsupported_option"; }
@ -388,7 +388,7 @@ const char* unsupported_option::name() const throw() { return "unsupported_optio
no_service_available::~no_service_available() throw() {} no_service_available::~no_service_available() throw() {}
no_service_available::no_service_available(const string& proto, const exception& other) no_service_available::no_service_available(const string& proto, const exception& other)
: messaging_exception(proto.empty() : net_exception(proto.empty()
? "No service available for this protocol." ? "No service available for this protocol."
: "No service available for this protocol: '" + proto + "'.", other) {} : "No service available for this protocol: '" + proto + "'.", other) {}
@ -402,7 +402,7 @@ const char* no_service_available::name() const throw() { return "no_service_avai
illegal_state::~illegal_state() throw() {} illegal_state::~illegal_state() throw() {}
illegal_state::illegal_state(const string& state, const exception& other) illegal_state::illegal_state(const string& state, const exception& other)
: messaging_exception("Illegal state to accomplish the operation: '" + state + "'.", other) {} : net_exception("Illegal state to accomplish the operation: '" + state + "'.", other) {}
exception* illegal_state::clone() const { return new illegal_state(*this); } exception* illegal_state::clone() const { return new illegal_state(*this); }
const char* illegal_state::name() const throw() { return "illegal_state"; } const char* illegal_state::name() const throw() { return "illegal_state"; }
@ -414,7 +414,7 @@ const char* illegal_state::name() const throw() { return "illegal_state"; }
folder_not_found::~folder_not_found() throw() {} folder_not_found::~folder_not_found() throw() {}
folder_not_found::folder_not_found(const exception& other) folder_not_found::folder_not_found(const exception& other)
: messaging_exception("Folder not found.", other) {} : net_exception("Folder not found.", other) {}
exception* folder_not_found::clone() const { return new folder_not_found(*this); } exception* folder_not_found::clone() const { return new folder_not_found(*this); }
const char* folder_not_found::name() const throw() { return "folder_not_found"; } const char* folder_not_found::name() const throw() { return "folder_not_found"; }
@ -426,7 +426,7 @@ const char* folder_not_found::name() const throw() { return "folder_not_found";
message_not_found::~message_not_found() throw() {} message_not_found::~message_not_found() throw() {}
message_not_found::message_not_found(const exception& other) message_not_found::message_not_found(const exception& other)
: messaging_exception("Message not found.", other) {} : net_exception("Message not found.", other) {}
exception* message_not_found::clone() const { return new message_not_found(*this); } exception* message_not_found::clone() const { return new message_not_found(*this); }
const char* message_not_found::name() const throw() { return "message_not_found"; } const char* message_not_found::name() const throw() { return "message_not_found"; }
@ -438,7 +438,7 @@ const char* message_not_found::name() const throw() { return "message_not_found"
operation_not_supported::~operation_not_supported() throw() {} operation_not_supported::~operation_not_supported() throw() {}
operation_not_supported::operation_not_supported(const exception& other) operation_not_supported::operation_not_supported(const exception& other)
: messaging_exception("Operation not supported.", other) {} : net_exception("Operation not supported.", other) {}
exception* operation_not_supported::clone() const { return new operation_not_supported(*this); } exception* operation_not_supported::clone() const { return new operation_not_supported(*this); }
const char* operation_not_supported::name() const throw() { return "operation_not_supported"; } const char* operation_not_supported::name() const throw() { return "operation_not_supported"; }
@ -450,7 +450,7 @@ const char* operation_not_supported::name() const throw() { return "operation_no
operation_timed_out::~operation_timed_out() throw() {} operation_timed_out::~operation_timed_out() throw() {}
operation_timed_out::operation_timed_out(const exception& other) operation_timed_out::operation_timed_out(const exception& other)
: messaging_exception("Operation timed out.", other) {} : net_exception("Operation timed out.", other) {}
exception* operation_timed_out::clone() const { return new operation_timed_out(*this); } exception* operation_timed_out::clone() const { return new operation_timed_out(*this); }
const char* operation_timed_out::name() const throw() { return "operation_timed_out"; } const char* operation_timed_out::name() const throw() { return "operation_timed_out"; }
@ -462,7 +462,7 @@ const char* operation_timed_out::name() const throw() { return "operation_timed_
operation_cancelled::~operation_cancelled() throw() {} operation_cancelled::~operation_cancelled() throw() {}
operation_cancelled::operation_cancelled(const exception& other) operation_cancelled::operation_cancelled(const exception& other)
: messaging_exception("Operation cancelled by the user.", other) {} : net_exception("Operation cancelled by the user.", other) {}
exception* operation_cancelled::clone() const { return new operation_cancelled(*this); } exception* operation_cancelled::clone() const { return new operation_cancelled(*this); }
const char* operation_cancelled::name() const throw() { return "operation_cancelled"; } const char* operation_cancelled::name() const throw() { return "operation_cancelled"; }
@ -474,7 +474,7 @@ const char* operation_cancelled::name() const throw() { return "operation_cancel
unfetched_object::~unfetched_object() throw() {} unfetched_object::~unfetched_object() throw() {}
unfetched_object::unfetched_object(const exception& other) unfetched_object::unfetched_object(const exception& other)
: messaging_exception("Object not fetched.", other) {} : net_exception("Object not fetched.", other) {}
exception* unfetched_object::clone() const { return new unfetched_object(*this); } exception* unfetched_object::clone() const { return new unfetched_object(*this); }
const char* unfetched_object::name() const throw() { return "unfetched_object"; } const char* unfetched_object::name() const throw() { return "unfetched_object"; }
@ -486,7 +486,7 @@ const char* unfetched_object::name() const throw() { return "unfetched_object";
not_connected::~not_connected() throw() {} not_connected::~not_connected() throw() {}
not_connected::not_connected(const exception& other) not_connected::not_connected(const exception& other)
: messaging_exception("Not connected to a service.", other) {} : net_exception("Not connected to a service.", other) {}
exception* not_connected::clone() const { return new not_connected(*this); } exception* not_connected::clone() const { return new not_connected(*this); }
const char* not_connected::name() const throw() { return "not_connected"; } const char* not_connected::name() const throw() { return "not_connected"; }
@ -498,7 +498,7 @@ const char* not_connected::name() const throw() { return "not_connected"; }
already_connected::~already_connected() throw() {} already_connected::~already_connected() throw() {}
already_connected::already_connected(const exception& other) already_connected::already_connected(const exception& other)
: messaging_exception("Already connected to a service. Disconnect and retry.", other) {} : net_exception("Already connected to a service. Disconnect and retry.", other) {}
exception* already_connected::clone() const { return new already_connected(*this); } exception* already_connected::clone() const { return new already_connected(*this); }
const char* already_connected::name() const throw() { return "already_connected"; } const char* already_connected::name() const throw() { return "already_connected"; }
@ -510,7 +510,7 @@ const char* already_connected::name() const throw() { return "already_connected"
illegal_operation::~illegal_operation() throw() {} illegal_operation::~illegal_operation() throw() {}
illegal_operation::illegal_operation(const string& msg, const exception& other) illegal_operation::illegal_operation(const string& msg, const exception& other)
: messaging_exception(msg.empty() : net_exception(msg.empty()
? "Illegal operation." ? "Illegal operation."
: "Illegal operation: " + msg + ".", : "Illegal operation: " + msg + ".",
other other
@ -527,7 +527,7 @@ const char* illegal_operation::name() const throw() { return "illegal_operation"
command_error::~command_error() throw() {} command_error::~command_error() throw() {}
command_error::command_error(const string& command, const string& response, command_error::command_error(const string& command, const string& response,
const string& desc, const exception& other) const string& desc, const exception& other)
: messaging_exception(desc.empty() : net_exception(desc.empty()
? "Error while executing command '" + command + "'." ? "Error while executing command '" + command + "'."
: "Error while executing command '" + command + "': " + desc + ".", : "Error while executing command '" + command + "': " + desc + ".",
other other
@ -548,7 +548,7 @@ const char* command_error::name() const throw() { return "command_error"; }
invalid_response::~invalid_response() throw() {} invalid_response::~invalid_response() throw() {}
invalid_response::invalid_response(const string& command, const string& response, const exception& other) invalid_response::invalid_response(const string& command, const string& response, const exception& other)
: messaging_exception(command.empty() : net_exception(command.empty()
? "Received invalid response." ? "Received invalid response."
: "Received invalid response for command '" + command + "'.", : "Received invalid response for command '" + command + "'.",
other other
@ -569,7 +569,7 @@ const char* invalid_response::name() const throw() { return "invalid_response";
partial_fetch_not_supported::~partial_fetch_not_supported() throw() {} partial_fetch_not_supported::~partial_fetch_not_supported() throw() {}
partial_fetch_not_supported::partial_fetch_not_supported(const exception& other) partial_fetch_not_supported::partial_fetch_not_supported(const exception& other)
: messaging_exception("Partial fetch not supported.", other) {} : net_exception("Partial fetch not supported.", other) {}
exception* partial_fetch_not_supported::clone() const { return new partial_fetch_not_supported(*this); } exception* partial_fetch_not_supported::clone() const { return new partial_fetch_not_supported(*this); }
const char* partial_fetch_not_supported::name() const throw() { return "partial_fetch_not_supported"; } const char* partial_fetch_not_supported::name() const throw() { return "partial_fetch_not_supported"; }
@ -581,7 +581,7 @@ const char* partial_fetch_not_supported::name() const throw() { return "partial_
malformed_url::~malformed_url() throw() {} malformed_url::~malformed_url() throw() {}
malformed_url::malformed_url(const string& error, const exception& other) malformed_url::malformed_url(const string& error, const exception& other)
: messaging_exception("Malformed URL: " + error + ".", other) {} : net_exception("Malformed URL: " + error + ".", other) {}
exception* malformed_url::clone() const { return new malformed_url(*this); } exception* malformed_url::clone() const { return new malformed_url(*this); }
const char* malformed_url::name() const throw() { return "malformed_url"; } const char* malformed_url::name() const throw() { return "malformed_url"; }
@ -593,7 +593,7 @@ const char* malformed_url::name() const throw() { return "malformed_url"; }
invalid_folder_name::~invalid_folder_name() throw() {} invalid_folder_name::~invalid_folder_name() throw() {}
invalid_folder_name::invalid_folder_name(const string& error, const exception& other) invalid_folder_name::invalid_folder_name(const string& error, const exception& other)
: messaging_exception(error.empty() : net_exception(error.empty()
? "Invalid folder name: " + error + "." ? "Invalid folder name: " + error + "."
: "Invalid folder name.", : "Invalid folder name.",
other) {} other) {}

105
src/net/authHelper.cpp Normal file
View File

@ -0,0 +1,105 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/authHelper.hpp"
#include "vmime/config.hpp"
#include "vmime/utility/md5.hpp"
namespace vmime {
namespace net {
//
// This code is based on the Sample Code published in the Appendix of
// the RFC-2104: "HMAC: Keyed-Hashing for Message Authentication".
//
void hmac_md5(const string& text, const string& key, string& hexDigest)
{
vmime_uint8 digest[16];
unsigned char ipad[65]; // inner padding - key XORd with ipad
unsigned char opad[65]; // outer padding - key XORd with opad
unsigned char tkey[16];
int tkeyLen;
// If key is longer than 64 bytes reset it to key = MD5(key)
if (key.length() > 64)
{
utility::md5 keyMD5;
keyMD5.update(reinterpret_cast <const vmime_uint8*>(key.data()), key.length());
std::copy(keyMD5.hash(), keyMD5.hash() + 16, tkey);
tkeyLen = 16;
}
else
{
std::copy(key.begin(), key.end(), tkey);
tkeyLen = key.length();
}
//
// the HMAC_MD5 transform looks like:
//
// MD5(K XOR opad, MD5(K XOR ipad, text))
//
// where K is an n byte key
// ipad is the byte 0x36 repeated 64 times
//
// opad is the byte 0x5c repeated 64 times
// and text is the data being protected
//
// Start out by storing key in pads
std::fill(ipad, ipad + sizeof(ipad), 0);
std::fill(opad, opad + sizeof(opad), 0);
std::copy(tkey, tkey + tkeyLen, ipad);
std::copy(tkey, tkey + tkeyLen, opad);
// XOR key with ipad and opad values
for (int i = 0 ; i < 64 ; ++i)
{
ipad[i] ^= 0x36;
opad[i] ^= 0x5c;
}
// Perform inner MD5
utility::md5 innerMD5;
innerMD5.update(ipad, 64);
innerMD5.update(text);
std::copy(innerMD5.hash(), innerMD5.hash() + 16, digest);
// Perform outer MD5
utility::md5 outerMD5;
outerMD5.update(opad, 64);
outerMD5.update(digest, 16);
//std::copy(outerMD5.hash(), outerMD5.hash() + 16, digest);
hexDigest = outerMD5.hex();
}
} // net
} // vmime

View File

@ -0,0 +1,52 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/authenticationInfos.hpp"
namespace vmime {
namespace net {
authenticationInfos::authenticationInfos(const string& username, const string& password)
: m_username(username), m_password(password)
{
}
authenticationInfos::authenticationInfos(const authenticationInfos& infos)
: object(), m_username(infos.m_username), m_password(infos.m_password)
{
}
const string& authenticationInfos::getUsername() const
{
return (m_username);
}
const string& authenticationInfos::getPassword() const
{
return (m_password);
}
} // net
} // vmime

33
src/net/authenticator.cpp Normal file
View File

@ -0,0 +1,33 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/authenticator.hpp"
namespace vmime {
namespace net {
authenticator::~authenticator()
{
}
} // net
} // vmime

View File

@ -0,0 +1,56 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_BUILDING_DOC
#define REGISTER_SERVICE(p_class, p_name) \
vmime::net::service::initializer <vmime::net::p_class> p_name(#p_name)
#if VMIME_BUILTIN_MESSAGING_PROTO_POP3
#include "vmime/net/pop3/POP3Store.hpp"
REGISTER_SERVICE(pop3::POP3Store, pop3);
#endif
#if VMIME_BUILTIN_MESSAGING_PROTO_SMTP
#include "vmime/net/smtp/SMTPTransport.hpp"
REGISTER_SERVICE(smtp::SMTPTransport, smtp);
#endif
#if VMIME_BUILTIN_MESSAGING_PROTO_IMAP
#include "vmime/net/imap/IMAPStore.hpp"
REGISTER_SERVICE(imap::IMAPStore, imap);
#endif
#if VMIME_BUILTIN_MESSAGING_PROTO_MAILDIR
#include "vmime/net/maildir/maildirStore.hpp"
REGISTER_SERVICE(maildir::maildirStore, maildir);
#endif
#if VMIME_BUILTIN_MESSAGING_PROTO_SENDMAIL
#include "vmime/net/sendmail/sendmailTransport.hpp"
REGISTER_SERVICE(sendmail::sendmailTransport, sendmail);
#endif
#endif // VMIME_BUILDING_DOC

View File

@ -0,0 +1,43 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/defaultAuthenticator.hpp"
#include "vmime/net/session.hpp"
namespace vmime {
namespace net {
defaultAuthenticator::defaultAuthenticator(weak_ref <session> sess, const string& prefix)
: m_session(sess), m_prefix(prefix)
{
}
const authenticationInfos defaultAuthenticator::requestAuthInfos() const
{
return (authenticationInfos
(m_session->getProperties()[m_prefix + "auth.username"],
m_session->getProperties()[m_prefix + "auth.password"]));
}
} // net
} // vmime

111
src/net/events.cpp Normal file
View File

@ -0,0 +1,111 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/events.hpp"
#include "vmime/net/folder.hpp"
#include <algorithm>
namespace vmime {
namespace net {
namespace events {
//
// messageCountEvent
//
messageCountEvent::messageCountEvent
(ref <folder> folder, const Types type, const std::vector <int>& nums)
: m_folder(folder), m_type(type)
{
m_nums.resize(nums.size());
std::copy(nums.begin(), nums.end(), m_nums.begin());
}
ref <const folder> messageCountEvent::getFolder() const { return (m_folder); }
const messageCountEvent::Types messageCountEvent::getType() const { return (m_type); }
const std::vector <int>& messageCountEvent::getNumbers() const { return (m_nums); }
void messageCountEvent::dispatch(messageCountListener* listener) const
{
if (m_type == TYPE_ADDED)
listener->messagesAdded(*this);
else
listener->messagesRemoved(*this);
}
//
// messageChangedEvent
//
messageChangedEvent::messageChangedEvent
(ref <folder> folder, const Types type, const std::vector <int>& nums)
: m_folder(folder), m_type(type)
{
m_nums.resize(nums.size());
std::copy(nums.begin(), nums.end(), m_nums.begin());
}
ref <const folder> messageChangedEvent::getFolder() const { return (m_folder); }
const messageChangedEvent::Types messageChangedEvent::getType() const { return (m_type); }
const std::vector <int>& messageChangedEvent::getNumbers() const { return (m_nums); }
void messageChangedEvent::dispatch(messageChangedListener* listener) const
{
listener->messageChanged(*this);
}
//
// folderEvent
//
folderEvent::folderEvent
(ref <folder> folder, const Types type,
const utility::path& oldPath, const utility::path& newPath)
: m_folder(folder), m_type(type), m_oldPath(oldPath), m_newPath(newPath)
{
}
ref <const folder> folderEvent::getFolder() const { return (m_folder); }
const folderEvent::Types folderEvent::getType() const { return (m_type); }
void folderEvent::dispatch(folderListener* listener) const
{
switch (m_type)
{
case TYPE_CREATED: listener->folderCreated(*this); break;
case TYPE_RENAMED: listener->folderRenamed(*this); break;
case TYPE_DELETED: listener->folderDeleted(*this); break;
}
}
} // events
} // net
} // vmime

96
src/net/folder.cpp Normal file
View File

@ -0,0 +1,96 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/folder.hpp"
#include <algorithm>
namespace vmime {
namespace net {
void folder::addMessageChangedListener(events::messageChangedListener* l)
{
m_messageChangedListeners.push_back(l);
}
void folder::removeMessageChangedListener(events::messageChangedListener* l)
{
std::remove(m_messageChangedListeners.begin(), m_messageChangedListeners.end(), l);
}
void folder::notifyMessageChanged(const events::messageChangedEvent& event)
{
for (std::list <events::messageChangedListener*>::iterator
it = m_messageChangedListeners.begin() ; it != m_messageChangedListeners.end() ; ++it)
{
event.dispatch(*it);
}
}
void folder::addMessageCountListener(events::messageCountListener* l)
{
m_messageCountListeners.push_back(l);
}
void folder::removeMessageCountListener(events::messageCountListener* l)
{
std::remove(m_messageCountListeners.begin(), m_messageCountListeners.end(), l);
}
void folder::notifyMessageCount(const events::messageCountEvent& event)
{
for (std::list <events::messageCountListener*>::iterator
it = m_messageCountListeners.begin() ; it != m_messageCountListeners.end() ; ++it)
{
event.dispatch(*it);
}
}
void folder::addFolderListener(events::folderListener* l)
{
m_folderListeners.push_back(l);
}
void folder::removeFolderListener(events::folderListener* l)
{
std::remove(m_folderListeners.begin(), m_folderListeners.end(), l);
}
void folder::notifyFolder(const events::folderEvent& event)
{
for (std::list <events::folderListener*>::iterator
it = m_folderListeners.begin() ; it != m_folderListeners.end() ; ++it)
{
event.dispatch(*it);
}
}
} // net
} // vmime

View File

@ -0,0 +1,313 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/imap/IMAPTag.hpp"
#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/net/imap/IMAPUtils.hpp"
#include "vmime/net/imap/IMAPStore.hpp"
#include "vmime/exception.hpp"
#include "vmime/platformDependant.hpp"
#include <sstream>
// Helpers for service properties
#define GET_PROPERTY(type, prop) \
(m_store->getInfos().getPropertyValue <type>(getSession(), \
dynamic_cast <const IMAPStore::_infos&>(m_store->getInfos()).getProperties().prop))
#define HAS_PROPERTY(prop) \
(m_store->getInfos().hasProperty(getSession(), \
dynamic_cast <const IMAPStore::_infos&>(m_store->getInfos()).getProperties().prop))
namespace vmime {
namespace net {
namespace imap {
IMAPConnection::IMAPConnection(weak_ref <IMAPStore> store, ref <authenticator> auth)
: m_store(store), m_auth(auth), m_socket(NULL), m_parser(NULL), m_tag(NULL),
m_hierarchySeparator('\0'), m_state(STATE_NONE), m_timeoutHandler(NULL)
{
}
IMAPConnection::~IMAPConnection()
{
if (isConnected())
disconnect();
else if (m_socket)
internalDisconnect();
}
void IMAPConnection::connect()
{
if (isConnected())
throw exceptions::already_connected();
m_state = STATE_NONE;
m_hierarchySeparator = '\0';
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 (HAS_PROPERTY(PROPERTY_TIMEOUT_FACTORY))
{
timeoutHandlerFactory* tof = platformDependant::getHandler()->
getTimeoutHandlerFactory(GET_PROPERTY(string, PROPERTY_TIMEOUT_FACTORY));
m_timeoutHandler = tof->create();
}
// Create and connect the socket
socketFactory* sf = platformDependant::getHandler()->
getSocketFactory(GET_PROPERTY(string, PROPERTY_SERVER_SOCKETFACTORY));
m_socket = sf->create();
m_socket->connect(address, port);
m_tag = vmime::create <IMAPTag>();
m_parser = vmime::create <IMAPParser>(m_tag, m_socket, m_timeoutHandler);
setState(STATE_NON_AUTHENTICATED);
// Connection greeting
//
// eg: C: <connection to server>
// --- S: * OK mydomain.org IMAP4rev1 v12.256 server ready
utility::auto_ptr <IMAPParser::greeting> greet(m_parser->readGreeting());
if (greet->resp_cond_bye())
{
internalDisconnect();
throw exceptions::connection_greeting_error(m_parser->lastLine());
}
else if (greet->resp_cond_auth()->condition() != IMAPParser::resp_cond_auth::PREAUTH)
{
const authenticationInfos auth = m_auth->requestAuthInfos();
// TODO: other authentication methods
send(true, "LOGIN " + IMAPUtils::quoteString(auth.getUsername())
+ " " + IMAPUtils::quoteString(auth.getPassword()), true);
utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
if (resp->isBad())
{
internalDisconnect();
throw exceptions::command_error("LOGIN", m_parser->lastLine());
}
else if (resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
internalDisconnect();
throw exceptions::authentication_error(m_parser->lastLine());
}
}
// Get the hierarchy separator character
initHierarchySeparator();
// Switch to state "Authenticated"
setState(STATE_AUTHENTICATED);
}
const bool IMAPConnection::isConnected() const
{
return (m_socket && m_socket->isConnected() &&
(m_state == STATE_AUTHENTICATED || m_state == STATE_SELECTED));
}
void IMAPConnection::disconnect()
{
if (!isConnected())
throw exceptions::not_connected();
internalDisconnect();
}
void IMAPConnection::internalDisconnect()
{
if (isConnected())
{
send(true, "LOGOUT", true);
m_socket->disconnect();
m_socket = NULL;
}
m_timeoutHandler = NULL;
m_state = STATE_LOGOUT;
}
void IMAPConnection::initHierarchySeparator()
{
send(true, "LIST \"\" \"\"", true);
vmime::utility::auto_ptr <IMAPParser::response> resp(m_parser->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
internalDisconnect();
throw exceptions::command_error("LIST", m_parser->lastLine(), "bad response");
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
if (respDataList.size() < 1 || respDataList[0]->response_data() == NULL)
{
internalDisconnect();
throw exceptions::command_error("LIST", m_parser->lastLine(), "unexpected response");
}
const IMAPParser::mailbox_data* mailboxData =
static_cast <const IMAPParser::response_data*>(respDataList[0]->response_data())->
mailbox_data();
if (mailboxData == NULL || mailboxData->type() != IMAPParser::mailbox_data::LIST)
{
internalDisconnect();
throw exceptions::command_error("LIST", m_parser->lastLine(), "invalid type");
}
if (mailboxData->mailbox_list()->quoted_char() == '\0')
{
internalDisconnect();
throw exceptions::command_error("LIST", m_parser->lastLine(), "no hierarchy separator");
}
m_hierarchySeparator = mailboxData->mailbox_list()->quoted_char();
}
void IMAPConnection::send(bool tag, const string& what, bool end)
{
#if VMIME_DEBUG
std::ostringstream oss;
if (tag)
{
++(*m_tag);
oss << string(*m_tag);
oss << " ";
}
oss << what;
if (end)
oss << "\r\n";
m_socket->send(oss.str());
#else
if (tag)
{
++(*m_tag);
m_socket->send(*m_tag);
m_socket->send(" ");
}
m_socket->send(what);
if (end)
{
m_socket->send("\r\n");
}
#endif
}
void IMAPConnection::sendRaw(const char* buffer, const int count)
{
m_socket->sendRaw(buffer, count);
}
IMAPParser::response* IMAPConnection::readResponse(IMAPParser::literalHandler* lh)
{
return (m_parser->readResponse(lh));
}
const IMAPConnection::ProtocolStates IMAPConnection::state() const
{
return (m_state);
}
void IMAPConnection::setState(const ProtocolStates state)
{
m_state = state;
}
const char IMAPConnection::hierarchySeparator() const
{
return (m_hierarchySeparator);
}
ref <const IMAPTag> IMAPConnection::getTag() const
{
return (m_tag);
}
ref <const IMAPParser> IMAPConnection::getParser() const
{
return (m_parser);
}
weak_ref <const IMAPStore> IMAPConnection::getStore() const
{
return (m_store);
}
weak_ref <IMAPStore> IMAPConnection::getStore()
{
return (m_store);
}
ref <session> IMAPConnection::getSession()
{
return (m_store->getSession());
}
} // imap
} // net
} // vmime

1608
src/net/imap/IMAPFolder.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,859 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/imap/IMAPParser.hpp"
#include "vmime/net/imap/IMAPMessage.hpp"
#include "vmime/net/imap/IMAPFolder.hpp"
#include "vmime/net/imap/IMAPStore.hpp"
#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/net/imap/IMAPUtils.hpp"
#include <sstream>
#include <iterator>
namespace vmime {
namespace net {
namespace imap {
//
// IMAPpart
//
class IMAPstructure;
class IMAPpart : public part
{
private:
friend class vmime::creator;
IMAPpart(weak_ref <IMAPpart> parent, const int number, const IMAPParser::body_type_mpart* mpart);
IMAPpart(weak_ref <IMAPpart> parent, const int number, const IMAPParser::body_type_1part* part);
public:
const structure& getStructure() const;
structure& getStructure();
weak_ref <const IMAPpart> getParent() const { return (m_parent); }
const mediaType& getType() const { return (m_mediaType); }
const int getSize() const { return (m_size); }
const int getNumber() const { return (m_number); }
const header& getHeader() const
{
if (m_header == NULL)
throw exceptions::unfetched_object();
else
return (*m_header);
}
static ref <IMAPpart> create
(weak_ref <IMAPpart> parent, const int number, const IMAPParser::body* body)
{
if (body->body_type_mpart())
return vmime::create <IMAPpart>(parent, number, body->body_type_mpart());
else
return vmime::create <IMAPpart>(parent, number, body->body_type_1part());
}
header& getOrCreateHeader()
{
if (m_header != NULL)
return (*m_header);
else
return (*(m_header = vmime::create <header>()));
}
private:
ref <IMAPstructure> m_structure;
weak_ref <IMAPpart> m_parent;
ref <header> m_header;
int m_number;
int m_size;
mediaType m_mediaType;
};
//
// IMAPstructure
//
class IMAPstructure : public structure
{
private:
IMAPstructure()
{
}
public:
IMAPstructure(const IMAPParser::body* body)
{
m_parts.push_back(IMAPpart::create(NULL, 1, body));
}
IMAPstructure(weak_ref <IMAPpart> parent, const std::vector <IMAPParser::body*>& list)
{
int number = 1;
for (std::vector <IMAPParser::body*>::const_iterator
it = list.begin() ; it != list.end() ; ++it, ++number)
{
m_parts.push_back(IMAPpart::create(parent, number, *it));
}
}
const part& operator[](const int x) const
{
return (*m_parts[x - 1]);
}
part& operator[](const int x)
{
return (*m_parts[x - 1]);
}
const int getCount() const
{
return (m_parts.size());
}
static IMAPstructure* emptyStructure()
{
return (&m_emptyStructure);
}
private:
static IMAPstructure m_emptyStructure;
std::vector <ref <IMAPpart> > m_parts;
};
IMAPstructure IMAPstructure::m_emptyStructure;
IMAPpart::IMAPpart(weak_ref <IMAPpart> parent, const int number, const IMAPParser::body_type_mpart* mpart)
: m_parent(parent), m_header(NULL), m_number(number), m_size(0)
{
m_mediaType = vmime::mediaType
("multipart", mpart->media_subtype()->value());
m_structure = vmime::create <IMAPstructure>
(thisWeakRef().dynamicCast <IMAPpart>(), mpart->list());
}
IMAPpart::IMAPpart(weak_ref <IMAPpart> parent, const int number, const IMAPParser::body_type_1part* part)
: m_parent(parent), m_header(NULL), m_number(number), m_size(0)
{
if (part->body_type_text())
{
m_mediaType = vmime::mediaType
("text", part->body_type_text()->
media_text()->media_subtype()->value());
m_size = part->body_type_text()->body_fields()->body_fld_octets()->value();
}
else if (part->body_type_msg())
{
m_mediaType = vmime::mediaType
("message", part->body_type_msg()->
media_message()->media_subtype()->value());
}
else
{
m_mediaType = vmime::mediaType
(part->body_type_basic()->media_basic()->media_type()->value(),
part->body_type_basic()->media_basic()->media_subtype()->value());
m_size = part->body_type_basic()->body_fields()->body_fld_octets()->value();
}
m_structure = NULL;
}
const class structure& IMAPpart::getStructure() const
{
if (m_structure != NULL)
return (*m_structure);
else
return (*IMAPstructure::emptyStructure());
}
class structure& IMAPpart::getStructure()
{
if (m_structure != NULL)
return (*m_structure);
else
return (*IMAPstructure::emptyStructure());
}
#ifndef VMIME_BUILDING_DOC
//
// IMAPMessage_literalHandler
//
class IMAPMessage_literalHandler : public IMAPParser::literalHandler
{
public:
IMAPMessage_literalHandler(utility::outputStream& os, utility::progressionListener* progress)
: m_os(os), m_progress(progress)
{
}
target* targetFor(const IMAPParser::component& comp, const int /* data */)
{
if (typeid(comp) == typeid(IMAPParser::msg_att_item))
{
const int type = static_cast
<const IMAPParser::msg_att_item&>(comp).type();
if (type == IMAPParser::msg_att_item::BODY_SECTION ||
type == IMAPParser::msg_att_item::RFC822_TEXT)
{
return new targetStream(m_progress, m_os);
}
}
return (NULL);
}
private:
utility::outputStream& m_os;
utility::progressionListener* m_progress;
};
#endif // VMIME_BUILDING_DOC
//
// IMAPMessage
//
IMAPMessage::IMAPMessage(IMAPFolder* folder, const int num)
: m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED),
m_expunged(false), m_structure(NULL)
{
m_folder->registerMessage(this);
}
IMAPMessage::~IMAPMessage()
{
if (m_folder)
m_folder->unregisterMessage(this);
}
void IMAPMessage::onFolderClosed()
{
m_folder = NULL;
}
const int IMAPMessage::getNumber() const
{
return (m_num);
}
const message::uid IMAPMessage::getUniqueId() const
{
return (m_uid);
}
const int IMAPMessage::getSize() const
{
if (m_size == -1)
throw exceptions::unfetched_object();
return (m_size);
}
const bool IMAPMessage::isExpunged() const
{
return (m_expunged);
}
const int IMAPMessage::getFlags() const
{
if (m_flags == FLAG_UNDEFINED)
throw exceptions::unfetched_object();
return (m_flags);
}
const structure& IMAPMessage::getStructure() const
{
if (m_structure == NULL)
throw exceptions::unfetched_object();
return (*m_structure);
}
structure& IMAPMessage::getStructure()
{
if (m_structure == NULL)
throw exceptions::unfetched_object();
return (*m_structure);
}
ref <const header> IMAPMessage::getHeader() const
{
if (m_header == NULL)
throw exceptions::unfetched_object();
return (m_header);
}
void IMAPMessage::extract(utility::outputStream& os, utility::progressionListener* progress,
const int start, const int length, const bool peek) const
{
if (!m_folder)
throw exceptions::folder_not_found();
extract(NULL, os, progress, start, length, false, peek);
}
void IMAPMessage::extractPart
(const part& p, utility::outputStream& os, utility::progressionListener* progress,
const int start, const int length, const bool peek) const
{
if (!m_folder)
throw exceptions::folder_not_found();
extract(&p, os, progress, start, length, false, peek);
}
void IMAPMessage::fetchPartHeader(part& p)
{
if (!m_folder)
throw exceptions::folder_not_found();
std::ostringstream oss;
utility::outputStreamAdapter ossAdapter(oss);
extract(&p, ossAdapter, NULL, 0, -1, true, true);
static_cast <IMAPpart&>(p).getOrCreateHeader().parse(oss.str());
}
void IMAPMessage::extract(const part* p, utility::outputStream& os,
utility::progressionListener* progress, const int start,
const int length, const bool headerOnly, const bool peek) const
{
IMAPMessage_literalHandler literalHandler(os, progress);
// Construct section identifier
std::ostringstream section;
if (p != NULL)
{
weak_ref <const IMAPpart> currentPart = static_cast <const IMAPpart*>(p);
std::vector <int> numbers;
numbers.push_back(currentPart->getNumber());
currentPart = currentPart->getParent();
while (currentPart != NULL)
{
numbers.push_back(currentPart->getNumber());
currentPart = currentPart->getParent();
}
numbers.erase(numbers.end() - 1);
for (std::vector <int>::reverse_iterator it = numbers.rbegin() ; it != numbers.rend() ; ++it)
{
if (it != numbers.rbegin()) section << ".";
section << *it;
}
}
// Build the request text
std::ostringstream command;
command << "FETCH " << m_num << " BODY";
if (peek) command << ".PEEK";
command << "[";
command << section.str();
if (headerOnly) command << ".MIME"; // "MIME" not "HEADER" for parts
command << "]";
if (start != 0 || length != -1)
command << "<" << start << "." << length << ">";
// Send the request
m_folder->m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp
(m_folder->m_connection->readResponse(&literalHandler));
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("FETCH",
m_folder->m_connection->getParser()->lastLine(), "bad response");
}
if (!headerOnly)
{
// TODO: update the flags (eg. flag "\Seen" may have been set)
}
}
void IMAPMessage::fetch(IMAPFolder* folder, const int options)
{
if (m_folder != folder)
throw exceptions::folder_not_found();
// TODO: optimization: send the request for multiple
// messages at the same time (FETCH x:y)
// Example:
// C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
// S: * 2 FETCH ....
// S: * 3 FETCH ....
// S: * 4 FETCH ....
// S: A654 OK FETCH completed
std::vector <string> items;
if (options & folder::FETCH_SIZE)
items.push_back("RFC822.SIZE");
if (options & folder::FETCH_FLAGS)
items.push_back("FLAGS");
if (options & folder::FETCH_STRUCTURE)
items.push_back("BODYSTRUCTURE");
if (options & folder::FETCH_UID)
items.push_back("UID");
if (options & folder::FETCH_FULL_HEADER)
items.push_back("RFC822.HEADER");
else
{
if (options & folder::FETCH_ENVELOPE)
items.push_back("ENVELOPE");
std::vector <string> headerFields;
if (options & folder::FETCH_CONTENT_INFO)
headerFields.push_back("CONTENT_TYPE");
if (options & folder::FETCH_IMPORTANCE)
{
headerFields.push_back("IMPORTANCE");
headerFields.push_back("X-PRIORITY");
}
if (!headerFields.empty())
{
string list;
for (std::vector <string>::iterator it = headerFields.begin() ;
it != headerFields.end() ; ++it)
{
if (it != headerFields.begin())
list += " ";
list += *it;
}
items.push_back("BODY[HEADER.FIELDS (" + list + ")]");
}
}
// Build the request text
std::ostringstream command;
command << "FETCH " << m_num << " (";
for (std::vector <string>::const_iterator it = items.begin() ;
it != items.end() ; ++it)
{
if (it != items.begin()) command << " ";
command << *it;
}
command << ")";
// Send the request
m_folder->m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_folder->m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("FETCH",
m_folder->m_connection->getParser()->lastLine(), "bad response");
}
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
{
throw exceptions::command_error("FETCH",
m_folder->m_connection->getParser()->lastLine(), "invalid response");
}
const IMAPParser::message_data* messageData =
(*it)->response_data()->message_data();
// We are only interested in responses of type "FETCH"
if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH)
continue;
if (static_cast <int>(messageData->number()) != m_num)
continue;
// Process fetch response for this message
processFetchResponse(options, messageData->msg_att());
}
}
void IMAPMessage::processFetchResponse
(const int options, const IMAPParser::msg_att* msgAtt)
{
// Get message attributes
const std::vector <IMAPParser::msg_att_item*> atts =
msgAtt->items();
int flags = 0;
for (std::vector <IMAPParser::msg_att_item*>::const_iterator
it = atts.begin() ; it != atts.end() ; ++it)
{
switch ((*it)->type())
{
case IMAPParser::msg_att_item::FLAGS:
{
flags |= IMAPUtils::messageFlagsFromFlags((*it)->flag_list());
break;
}
case IMAPParser::msg_att_item::UID:
{
std::ostringstream oss;
oss << m_folder->m_uidValidity << ":" << (*it)->unique_id()->value();
m_uid = oss.str();
break;
}
case IMAPParser::msg_att_item::ENVELOPE:
{
if (!(options & folder::FETCH_FULL_HEADER))
{
const IMAPParser::envelope* env = (*it)->envelope();
ref <vmime::header> hdr = getOrCreateHeader();
// Date
hdr->Date()->setValue(env->env_date()->value());
// Subject
text subject;
text::decodeAndUnfold(env->env_subject()->value(), &subject);
hdr->Subject()->setValue(subject);
// From
mailboxList from;
convertAddressList(*(env->env_from()), from);
if (!from.isEmpty())
hdr->From()->setValue(*(from.getMailboxAt(0)));
// To
mailboxList to;
convertAddressList(*(env->env_to()), to);
hdr->To()->setValue(to);
// Sender
mailboxList sender;
convertAddressList(*(env->env_sender()), sender);
if (!sender.isEmpty())
hdr->Sender()->setValue(*(sender.getMailboxAt(0)));
// Reply-to
mailboxList replyTo;
convertAddressList(*(env->env_reply_to()), replyTo);
if (!replyTo.isEmpty())
hdr->ReplyTo()->setValue(*(replyTo.getMailboxAt(0)));
// Cc
mailboxList cc;
convertAddressList(*(env->env_cc()), cc);
if (!cc.isEmpty())
hdr->Cc()->setValue(cc);
// Bcc
mailboxList bcc;
convertAddressList(*(env->env_bcc()), bcc);
if (!bcc.isEmpty())
hdr->Bcc()->setValue(bcc);
}
break;
}
case IMAPParser::msg_att_item::BODY_STRUCTURE:
{
m_structure = vmime::create <IMAPstructure>((*it)->body());
break;
}
case IMAPParser::msg_att_item::RFC822_HEADER:
{
getOrCreateHeader()->parse((*it)->nstring()->value());
break;
}
case IMAPParser::msg_att_item::RFC822_SIZE:
{
m_size = (*it)->number()->value();
break;
}
case IMAPParser::msg_att_item::BODY_SECTION:
{
if (!(options & folder::FETCH_FULL_HEADER))
{
if ((*it)->section()->section_text1() &&
(*it)->section()->section_text1()->type()
== IMAPParser::section_text::HEADER_FIELDS)
{
header tempHeader;
tempHeader.parse((*it)->nstring()->value());
vmime::header& hdr = *getOrCreateHeader();
std::vector <ref <headerField> > fields = tempHeader.getFieldList();
for (std::vector <ref <headerField> >::const_iterator jt = fields.begin() ;
jt != fields.end() ; ++jt)
{
hdr.appendField((*jt)->clone().dynamicCast <headerField>());
}
}
}
break;
}
case IMAPParser::msg_att_item::INTERNALDATE:
case IMAPParser::msg_att_item::RFC822:
case IMAPParser::msg_att_item::RFC822_TEXT:
case IMAPParser::msg_att_item::BODY:
{
break;
}
}
}
if (options & folder::FETCH_FLAGS)
m_flags = flags;
}
ref <header> IMAPMessage::getOrCreateHeader()
{
if (m_header != NULL)
return (m_header);
else
return (m_header = vmime::create <header>());
}
void IMAPMessage::convertAddressList
(const IMAPParser::address_list& src, mailboxList& dest)
{
for (std::vector <IMAPParser::address*>::const_iterator
it = src.addresses().begin() ; it != src.addresses().end() ; ++it)
{
const IMAPParser::address& addr = **it;
text name;
text::decodeAndUnfold(addr.addr_name()->value(), &name);
string email = addr.addr_mailbox()->value()
+ "@" + addr.addr_host()->value();
dest.appendMailbox(vmime::create <mailbox>(name, email));
}
}
void IMAPMessage::setFlags(const int flags, const int mode)
{
if (!m_folder)
throw exceptions::folder_not_found();
else if (m_folder->m_mode == folder::MODE_READ_ONLY)
throw exceptions::illegal_state("Folder is read-only");
// Build the request text
std::ostringstream command;
command << "STORE " << m_num;
switch (mode)
{
case FLAG_MODE_ADD: command << " +FLAGS"; break;
case FLAG_MODE_REMOVE: command << " -FLAGS"; break;
default:
case FLAG_MODE_SET: command << " FLAGS"; break;
}
if (m_flags == FLAG_UNDEFINED) // Update local flags only if they
command << ".SILENT "; // have been fetched previously
else
command << " ";
std::vector <string> flagList;
if (flags & FLAG_REPLIED) flagList.push_back("\\Answered");
if (flags & FLAG_MARKED) flagList.push_back("\\Flagged");
if (flags & FLAG_DELETED) flagList.push_back("\\Deleted");
if (flags & FLAG_SEEN) flagList.push_back("\\Seen");
if (!flagList.empty())
{
command << "(";
if (flagList.size() >= 2)
{
std::copy(flagList.begin(), flagList.end() - 1,
std::ostream_iterator <string>(command, " "));
}
command << *(flagList.end() - 1) << ")";
// Send the request
m_folder->m_connection->send(true, command.str(), true);
// Get the response
utility::auto_ptr <IMAPParser::response> resp(m_folder->m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("STORE",
m_folder->m_connection->getParser()->lastLine(), "bad response");
}
// Update the local flags for this message
if (m_flags != FLAG_UNDEFINED)
{
const std::vector <IMAPParser::continue_req_or_response_data*>& respDataList =
resp->continue_req_or_response_data();
int newFlags = 0;
for (std::vector <IMAPParser::continue_req_or_response_data*>::const_iterator
it = respDataList.begin() ; it != respDataList.end() ; ++it)
{
if ((*it)->response_data() == NULL)
continue;
const IMAPParser::message_data* messageData =
(*it)->response_data()->message_data();
// We are only interested in responses of type "FETCH"
if (messageData == NULL || messageData->type() != IMAPParser::message_data::FETCH)
continue;
// Get message attributes
const std::vector <IMAPParser::msg_att_item*> atts =
messageData->msg_att()->items();
for (std::vector <IMAPParser::msg_att_item*>::const_iterator
it = atts.begin() ; it != atts.end() ; ++it)
{
if ((*it)->type() == IMAPParser::msg_att_item::FLAGS)
newFlags |= IMAPUtils::messageFlagsFromFlags((*it)->flag_list());
}
}
m_flags = newFlags;
}
// Notify message flags changed
std::vector <int> nums;
nums.push_back(m_num);
events::messageChangedEvent event
(m_folder->thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, nums);
for (std::list <IMAPFolder*>::iterator it = m_folder->m_store->m_folders.begin() ;
it != m_folder->m_store->m_folders.end() ; ++it)
{
if ((*it)->getFullPath() == m_folder->m_path)
(*it)->notifyMessageChanged(event);
}
}
}
} // imap
} // net
} // vmime

308
src/net/imap/IMAPStore.cpp Normal file
View File

@ -0,0 +1,308 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/imap/IMAPStore.hpp"
#include "vmime/net/imap/IMAPFolder.hpp"
#include "vmime/net/imap/IMAPConnection.hpp"
#include "vmime/exception.hpp"
#include "vmime/platformDependant.hpp"
#include <map>
namespace vmime {
namespace net {
namespace imap {
#ifndef VMIME_BUILDING_DOC
//
// IMAPauthenticator: private class used internally
//
// Used to request user credentials only in the first authentication
// and reuse this information the next times
//
class IMAPauthenticator : public authenticator
{
public:
IMAPauthenticator(ref <authenticator> auth)
: m_auth(auth), m_infos(NULL)
{
}
~IMAPauthenticator()
{
}
const authenticationInfos requestAuthInfos() const
{
if (m_infos == NULL)
m_infos = vmime::create <authenticationInfos>(m_auth->requestAuthInfos());
return (*m_infos);
}
private:
ref <authenticator> m_auth;
mutable ref <authenticationInfos> m_infos;
};
#endif // VMIME_BUILDING_DOC
//
// IMAPStore
//
IMAPStore::IMAPStore(ref <session> sess, ref <authenticator> auth)
: store(sess, getInfosInstance(), auth),
m_connection(NULL), m_oneTimeAuth(NULL)
{
}
IMAPStore::~IMAPStore()
{
if (isConnected())
disconnect();
}
ref <authenticator> IMAPStore::oneTimeAuthenticator()
{
return (m_oneTimeAuth);
}
const string IMAPStore::getProtocolName() const
{
return "imap";
}
ref <folder> IMAPStore::getRootFolder()
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <IMAPFolder>(folder::path(), this);
}
ref <folder> IMAPStore::getDefaultFolder()
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <IMAPFolder>(folder::path::component("INBOX"), this);
}
ref <folder> IMAPStore::getFolder(const folder::path& path)
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <IMAPFolder>(path, this);
}
const bool IMAPStore::isValidFolderName(const folder::path::component& /* name */) const
{
return true;
}
void IMAPStore::connect()
{
if (isConnected())
throw exceptions::already_connected();
m_oneTimeAuth = vmime::create <IMAPauthenticator>(getAuthenticator());
m_connection = vmime::create <IMAPConnection>
(thisWeakRef().dynamicCast <IMAPStore>(), m_oneTimeAuth);
try
{
m_connection->connect();
}
catch (std::exception&)
{
m_connection = NULL;
throw;
}
}
const bool IMAPStore::isConnected() const
{
return (m_connection && m_connection->isConnected());
}
void IMAPStore::disconnect()
{
if (!isConnected())
throw exceptions::not_connected();
for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ;
it != m_folders.end() ; ++it)
{
(*it)->onStoreDisconnected();
}
m_folders.clear();
m_connection->disconnect();
m_oneTimeAuth = NULL;
m_connection = NULL;
}
void IMAPStore::noop()
{
if (!isConnected())
throw exceptions::not_connected();
m_connection->send(true, "NOOP", true);
utility::auto_ptr <IMAPParser::response> resp(m_connection->readResponse());
if (resp->isBad() || resp->response_done()->response_tagged()->
resp_cond_state()->status() != IMAPParser::resp_cond_state::OK)
{
throw exceptions::command_error("NOOP", m_connection->getParser()->lastLine());
}
}
ref <IMAPConnection> IMAPStore::connection()
{
return (m_connection);
}
void IMAPStore::registerFolder(IMAPFolder* folder)
{
m_folders.push_back(folder);
}
void IMAPStore::unregisterFolder(IMAPFolder* folder)
{
std::list <IMAPFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
if (it != m_folders.end()) m_folders.erase(it);
}
const int IMAPStore::getCapabilities() const
{
return (CAPABILITY_CREATE_FOLDER |
CAPABILITY_RENAME_FOLDER |
CAPABILITY_ADD_MESSAGE |
CAPABILITY_COPY_MESSAGE |
CAPABILITY_DELETE_MESSAGE |
CAPABILITY_PARTIAL_FETCH |
CAPABILITY_MESSAGE_FLAGS |
CAPABILITY_EXTRACT_PART);
}
// Service infos
IMAPStore::_infos IMAPStore::sm_infos;
const serviceInfos& IMAPStore::getInfosInstance()
{
return (sm_infos);
}
const serviceInfos& IMAPStore::getInfos() const
{
return (sm_infos);
}
const string IMAPStore::_infos::getPropertyPrefix() const
{
return "store.imap.";
}
const IMAPStore::_infos::props& IMAPStore::_infos::getProperties() const
{
static props p =
{
// IMAP-specific options
// (none)
// Common properties
property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
property(serviceInfos::property::SERVER_PORT, "143"),
property(serviceInfos::property::SERVER_SOCKETFACTORY),
property(serviceInfos::property::TIMEOUT_FACTORY)
};
return p;
}
const std::vector <serviceInfos::property> IMAPStore::_infos::getAvailableProperties() const
{
std::vector <property> list;
const props& p = getProperties();
// IMAP-specific options
// (none)
// Common properties
list.push_back(p.PROPERTY_AUTH_USERNAME);
list.push_back(p.PROPERTY_AUTH_PASSWORD);
list.push_back(p.PROPERTY_SERVER_ADDRESS);
list.push_back(p.PROPERTY_SERVER_PORT);
list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY);
list.push_back(p.PROPERTY_TIMEOUT_FACTORY);
return (list);
}
} // imap
} // net
} // vmime

99
src/net/imap/IMAPTag.cpp Normal file
View File

@ -0,0 +1,99 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/imap/IMAPTag.hpp"
namespace vmime {
namespace net {
namespace imap {
const int IMAPTag::sm_maxNumber = 52 * 10 * 10 * 10;
IMAPTag::IMAPTag(const int number)
: m_number(number)
{
m_tag.resize(4);
}
IMAPTag::IMAPTag(const IMAPTag& tag)
: object(), m_number(tag.m_number)
{
m_tag.resize(4);
}
IMAPTag::IMAPTag()
: m_number(0)
{
m_tag.resize(4);
}
IMAPTag& IMAPTag::operator++()
{
++m_number;
if (m_number >= sm_maxNumber)
m_number = 1;
generate();
return (*this);
}
const IMAPTag IMAPTag::operator++(int)
{
IMAPTag old(*this);
operator++();
return (old);
}
const int IMAPTag::number() const
{
return (m_number);
}
IMAPTag::operator string() const
{
return (m_tag);
}
void IMAPTag::generate()
{
static const char prefixChars[53] =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
m_tag[0] = prefixChars[m_number / 1000];
m_tag[1] = '0' + (m_number % 1000) / 100;
m_tag[2] = '0' + (m_number % 100) / 10;
m_tag[3] = '0' + (m_number % 10);
}
} // imap
} // net
} // vmime

555
src/net/imap/IMAPUtils.cpp Normal file
View File

@ -0,0 +1,555 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/imap/IMAPUtils.hpp"
#include "vmime/net/message.hpp"
#include <sstream>
#include <iterator>
#include <algorithm>
namespace vmime {
namespace net {
namespace imap {
const string IMAPUtils::quoteString(const string& text)
{
//
// ATOM_CHAR ::= <any CHAR except atom_specials>
//
// atom_specials ::= "(" / ")" / "{" / SPACE / CTL /
// list_wildcards / quoted_specials
//
// list_wildcards ::= "%" / "*"
//
// quoted_specials ::= <"> / "\"
//
// CHAR ::= <any 7-bit US-ASCII character except NUL,
// 0x01 - 0x7f>
//
// CTL ::= <any ASCII control character and DEL,
// 0x00 - 0x1f, 0x7f>
//
bool needQuoting = text.empty();
for (string::const_iterator it = text.begin() ;
!needQuoting && it != text.end() ; ++it)
{
const unsigned char c = *it;
switch (c)
{
case '(':
case ')':
case '{':
case 0x20: // SPACE
case '%':
case '*':
case '"':
case '\\':
needQuoting = true;
break;
default:
if (c <= 0x1f || c >= 0x7f)
needQuoting = true;
}
}
if (needQuoting)
{
string quoted;
quoted.reserve((text.length() * 3) / 2 + 2);
quoted += '"';
for (string::const_iterator it = text.begin() ;
!needQuoting && it != text.end() ; ++it)
{
const unsigned char c = *it;
if (c == '\\' || c == '"')
quoted += '\\';
quoted += c;
}
quoted += '"';
return (quoted);
}
else
{
return (text);
}
}
const string IMAPUtils::pathToString
(const char hierarchySeparator, const folder::path& path)
{
string result;
for (int i = 0 ; i < path.getSize() ; ++i)
{
if (i > 0) result += hierarchySeparator;
result += toModifiedUTF7(hierarchySeparator, path[i]);
}
return (result);
}
const folder::path IMAPUtils::stringToPath
(const char hierarchySeparator, const string& str)
{
folder::path result;
string::const_iterator begin = str.begin();
for (string::const_iterator it = str.begin() ; it != str.end() ; ++it)
{
if (*it == hierarchySeparator)
{
result /= fromModifiedUTF7(string(begin, it));
begin = it + 1;
}
}
if (begin != str.end())
{
result /= fromModifiedUTF7(string(begin, str.end()));
}
return (result);
}
const string IMAPUtils::toModifiedUTF7
(const char hierarchySeparator, const folder::path::component& text)
{
// We will replace the hierarchy separator with an equivalent
// UTF-7 sequence, so we compute it here...
const char base64alphabet[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,=";
const unsigned int hs = static_cast <unsigned int>(static_cast <unsigned char>(hierarchySeparator));
string hsUTF7;
hsUTF7.resize(3);
hsUTF7[0] = base64alphabet[0];
hsUTF7[1] = base64alphabet[(hs & 0xF0) >> 4];
hsUTF7[2] = base64alphabet[(hs & 0x0F) << 2];
// Transcode path component to UTF-7 charset.
// WARNING: This may throw "exceptions::charset_conv_error"
const string cvt = text.getConvertedText(charset(charsets::UTF_7));
// Transcode to modified UTF-7 (RFC-2060).
string out;
out.reserve((cvt.length() * 3) / 2);
bool inB64sequence = false;
for (string::const_iterator it = cvt.begin() ; it != cvt.end() ; ++it)
{
const unsigned char c = *it;
// Replace hierarchy separator with an equivalent UTF-7 Base64 sequence
if (!inB64sequence && c == hierarchySeparator)
{
out += "&" + hsUTF7 + "-";
continue;
}
switch (c)
{
// Beginning of Base64 sequence: replace '+' with '&'
case '+':
{
if (!inB64sequence)
{
inB64sequence = true;
out += '&';
}
else
{
out += '+';
}
break;
}
// End of Base64 sequence
case '-':
{
inB64sequence = false;
out += '-';
break;
}
// ',' is used instead of '/' in modified Base64
case '/':
{
out += inB64sequence ? ',' : '/';
break;
}
// '&' (0x26) is represented by the two-octet sequence "&-"
case '&':
{
if (!inB64sequence)
out += "&-";
else
out += '&';
break;
}
default:
{
out += c;
break;
}
}
}
return (out);
}
const folder::path::component IMAPUtils::fromModifiedUTF7(const string& text)
{
// Transcode from modified UTF-7 (RFC-2060).
string out;
out.reserve(text.length());
bool inB64sequence = false;
unsigned char prev = 0;
for (string::const_iterator it = text.begin() ; it != text.end() ; ++it)
{
const unsigned char c = *it;
switch (c)
{
// Start of Base64 sequence
case '&':
{
if (!inB64sequence)
{
inB64sequence = true;
out += '+';
}
else
{
out += '&';
}
break;
}
// End of Base64 sequence (or "&-" --> "&")
case '-':
{
if (inB64sequence && prev == '&')
out += '&';
else
out += '-';
inB64sequence = false;
break;
}
// ',' is used instead of '/' in modified Base64
case ',':
{
out += (inB64sequence ? '/' : ',');
break;
}
default:
{
out += c;
break;
}
}
prev = c;
}
// Store it as UTF-8 by default
string cvt;
charset::convert(out, cvt,
charset(charsets::UTF_7), charset(charsets::UTF_8));
return (folder::path::component(cvt, charset(charsets::UTF_8)));
}
const int IMAPUtils::folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list)
{
// Get folder type
int type = folder::TYPE_CONTAINS_MESSAGES | folder::TYPE_CONTAINS_FOLDERS;
const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags();
for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
it != flags.end() ; ++it)
{
if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT)
type &= ~folder::TYPE_CONTAINS_MESSAGES;
}
if (type & folder::TYPE_CONTAINS_MESSAGES)
type &= ~folder::TYPE_CONTAINS_FOLDERS;
return (type);
}
const int IMAPUtils::folderFlagsFromFlags(const IMAPParser::mailbox_flag_list* list)
{
// Get folder flags
int folderFlags = folder::FLAG_CHILDREN;
const std::vector <IMAPParser::mailbox_flag*>& flags = list->flags();
for (std::vector <IMAPParser::mailbox_flag*>::const_iterator it = flags.begin() ;
it != flags.end() ; ++it)
{
if ((*it)->type() == IMAPParser::mailbox_flag::NOSELECT)
folderFlags |= folder::FLAG_NO_OPEN;
else if ((*it)->type() == IMAPParser::mailbox_flag::NOINFERIORS)
folderFlags &= ~folder::FLAG_CHILDREN;
}
return (folderFlags);
}
const int IMAPUtils::messageFlagsFromFlags(const IMAPParser::flag_list* list)
{
const std::vector <IMAPParser::flag*>& flagList = list->flags();
int flags = 0;
for (std::vector <IMAPParser::flag*>::const_iterator
it = flagList.begin() ; it != flagList.end() ; ++it)
{
switch ((*it)->type())
{
case IMAPParser::flag::ANSWERED:
flags |= message::FLAG_REPLIED;
break;
case IMAPParser::flag::FLAGGED:
flags |= message::FLAG_MARKED;
break;
case IMAPParser::flag::DELETED:
flags |= message::FLAG_DELETED;
break;
case IMAPParser::flag::SEEN:
flags |= message::FLAG_SEEN;
break;
default:
//case IMAPParser::flag::UNKNOWN:
//case IMAPParser::flag::DRAFT:
break;
}
}
return (flags);
}
const string IMAPUtils::messageFlagList(const int flags)
{
std::vector <string> flagList;
if (flags & message::FLAG_REPLIED) flagList.push_back("\\Answered");
if (flags & message::FLAG_MARKED) flagList.push_back("\\Flagged");
if (flags & message::FLAG_DELETED) flagList.push_back("\\Deleted");
if (flags & message::FLAG_SEEN) flagList.push_back("\\Seen");
if (!flagList.empty())
{
std::ostringstream res;
res << "(";
if (flagList.size() >= 2)
{
std::copy(flagList.begin(), flagList.end() - 1,
std::ostream_iterator <string>(res, " "));
}
res << *(flagList.end() - 1) << ")";
return (res.str());
}
return "";
}
// This function builds a "IMAP set" given a list. Try to group consecutive
// message numbers to reduce the list.
//
// Example:
// IN = "1,2,3,4,5,7,8,13,15,16,17"
// OUT = "1:5,7:8,13,15:*" for a mailbox with a total of 17 messages (max = 17)
const string IMAPUtils::listToSet(const std::vector <int>& list, const int max,
const bool alreadySorted)
{
// Sort a copy of the list (if not already sorted)
std::vector <int> temp;
if (!alreadySorted)
{
temp.resize(list.size());
std::copy(list.begin(), list.end(), temp.begin());
std::sort(temp.begin(), temp.end());
}
const std::vector <int>& theList = (alreadySorted ? list : temp);
// Build the set
std::ostringstream res;
int previous = -1, setBegin = -1;
for (std::vector <int>::const_iterator it = theList.begin() ;
it != theList.end() ; ++it)
{
const int current = *it;
if (previous == -1)
{
res << current;
previous = current;
setBegin = current;
}
else
{
if (current == previous + 1)
{
previous = current;
}
else
{
if (setBegin != previous)
{
res << ":" << previous << "," << current;
previous = current;
setBegin = current;
}
else
{
if (setBegin != current) // skip duplicates
res << "," << current;
previous = current;
setBegin = current;
}
}
}
}
if (previous != setBegin)
{
if (previous == max)
res << ":*";
else
res << ":" << previous;
}
return (res.str());
}
const string IMAPUtils::dateTime(const vmime::datetime& date)
{
std::ostringstream res;
// date_time ::= <"> date_day_fixed "-" date_month "-" date_year
// SPACE time SPACE zone <">
//
// time ::= 2digit ":" 2digit ":" 2digit
// ;; Hours minutes seconds
// zone ::= ("+" / "-") 4digit
// ;; Signed four-digit value of hhmm representing
// ;; hours and minutes west of Greenwich
res << '"';
// Date
if (date.getDay() < 10) res << ' ';
res << date.getDay();
res << '-';
static const char* monthNames[12] =
{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
res << monthNames[std::min(std::max(date.getMonth() - 1, 0), 11)];
res << '-';
if (date.getYear() < 10) res << '0';
if (date.getYear() < 100) res << '0';
if (date.getYear() < 1000) res << '0';
res << date.getYear();
res << ' ';
// Time
if (date.getHour() < 10) res << '0';
res << date.getHour() << ':';
if (date.getMinute() < 10) res << '0';
res << date.getMinute() << ':';
if (date.getSecond() < 10) res << '0';
res << date.getSecond();
res << ' ';
// Zone
const int zs = (date.getZone() < 0 ? -1 : 1);
const int zh = (date.getZone() * zs) / 60;
const int zm = (date.getZone() * zs) % 60;
res << (zs < 0 ? '-' : '+');
if (zh < 10) res << '0';
res << zh;
if (zm < 10) res << '0';
res << zm;
res << '"';
return (res.str());
}
} // imap
} // net
} // vmime

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,505 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/maildir/maildirMessage.hpp"
#include "vmime/net/maildir/maildirFolder.hpp"
#include "vmime/net/maildir/maildirUtils.hpp"
#include "vmime/net/maildir/maildirStore.hpp"
#include "vmime/message.hpp"
#include "vmime/exception.hpp"
#include "vmime/platformDependant.hpp"
namespace vmime {
namespace net {
namespace maildir {
//
// maildirPart
//
class maildirStructure;
class maildirPart : public part
{
public:
maildirPart(weak_ref <maildirPart> parent, const int number, const bodyPart& part);
~maildirPart();
const structure& getStructure() const;
structure& getStructure();
weak_ref <const maildirPart> getParent() const { return (m_parent); }
const mediaType& getType() const { return (m_mediaType); }
const int getSize() const { return (m_size); }
const int getNumber() const { return (m_number); }
const header& getHeader() const
{
if (m_header == NULL)
throw exceptions::unfetched_object();
else
return (*m_header);
}
header& getOrCreateHeader()
{
if (m_header != NULL)
return (*m_header);
else
return (*(m_header = vmime::create <header>()));
}
const int getHeaderParsedOffset() const { return (m_headerParsedOffset); }
const int getHeaderParsedLength() const { return (m_headerParsedLength); }
const int getBodyParsedOffset() const { return (m_bodyParsedOffset); }
const int getBodyParsedLength() const { return (m_bodyParsedLength); }
private:
ref <maildirStructure> m_structure;
weak_ref <maildirPart> m_parent;
ref <header> m_header;
int m_number;
int m_size;
mediaType m_mediaType;
int m_headerParsedOffset;
int m_headerParsedLength;
int m_bodyParsedOffset;
int m_bodyParsedLength;
};
//
// maildirStructure
//
class maildirStructure : public structure
{
private:
maildirStructure()
{
}
public:
maildirStructure(weak_ref <maildirPart> parent, const bodyPart& part)
{
m_parts.push_back(vmime::create <maildirPart>(parent, 1, part));
}
maildirStructure(weak_ref <maildirPart> parent, const std::vector <ref <const vmime::bodyPart> >& list)
{
int number = 1;
for (unsigned int i = 0 ; i < list.size() ; ++i)
m_parts.push_back(vmime::create <maildirPart>(parent, number, *list[i]));
}
const part& operator[](const int x) const
{
return (*m_parts[x - 1]);
}
part& operator[](const int x)
{
return (*m_parts[x - 1]);
}
const int getCount() const
{
return (m_parts.size());
}
static maildirStructure* emptyStructure()
{
return (&m_emptyStructure);
}
private:
static maildirStructure m_emptyStructure;
std::vector <ref <maildirPart> > m_parts;
};
maildirStructure maildirStructure::m_emptyStructure;
maildirPart::maildirPart(weak_ref <maildirPart> parent, const int number, const bodyPart& part)
: m_parent(parent), m_header(NULL), m_number(number)
{
if (part.getBody()->getPartList().size() == 0)
m_structure = NULL;
else
{
m_structure = vmime::create <maildirStructure>
(thisWeakRef().dynamicCast <maildirPart>(),
part.getBody()->getPartList());
}
m_headerParsedOffset = part.getHeader()->getParsedOffset();
m_headerParsedLength = part.getHeader()->getParsedLength();
m_bodyParsedOffset = part.getBody()->getParsedOffset();
m_bodyParsedLength = part.getBody()->getParsedLength();
m_size = part.getBody()->getContents()->getLength();
m_mediaType = part.getBody()->getContentType();
}
maildirPart::~maildirPart()
{
}
const structure& maildirPart::getStructure() const
{
if (m_structure != NULL)
return (*m_structure);
else
return (*maildirStructure::emptyStructure());
}
structure& maildirPart::getStructure()
{
if (m_structure != NULL)
return (*m_structure);
else
return (*maildirStructure::emptyStructure());
}
//
// maildirMessage
//
maildirMessage::maildirMessage(weak_ref <maildirFolder> folder, const int num)
: m_folder(folder), m_num(num), m_size(-1), m_flags(FLAG_UNDEFINED),
m_expunged(false), m_structure(NULL)
{
m_folder->registerMessage(this);
}
maildirMessage::~maildirMessage()
{
if (m_folder)
m_folder->unregisterMessage(this);
}
void maildirMessage::onFolderClosed()
{
m_folder = NULL;
}
const int maildirMessage::getNumber() const
{
return (m_num);
}
const message::uid maildirMessage::getUniqueId() const
{
return (m_uid);
}
const int maildirMessage::getSize() const
{
if (m_size == -1)
throw exceptions::unfetched_object();
return (m_size);
}
const bool maildirMessage::isExpunged() const
{
return (m_expunged);
}
const structure& maildirMessage::getStructure() const
{
if (m_structure == NULL)
throw exceptions::unfetched_object();
return (*m_structure);
}
structure& maildirMessage::getStructure()
{
if (m_structure == NULL)
throw exceptions::unfetched_object();
return (*m_structure);
}
ref <const header> maildirMessage::getHeader() const
{
if (m_header == NULL)
throw exceptions::unfetched_object();
return (m_header);
}
const int maildirMessage::getFlags() const
{
if (m_flags == FLAG_UNDEFINED)
throw exceptions::unfetched_object();
return (m_flags);
}
void maildirMessage::setFlags(const int flags, const int mode)
{
if (!m_folder)
throw exceptions::folder_not_found();
m_folder->setMessageFlags(m_num, m_num, flags, mode);
}
void maildirMessage::extract(utility::outputStream& os,
utility::progressionListener* progress, const int start,
const int length, const bool peek) const
{
extractImpl(os, progress, 0, m_size, start, length, peek);
}
void maildirMessage::extractPart(const part& p, utility::outputStream& os,
utility::progressionListener* progress, const int start,
const int length, const bool peek) const
{
const maildirPart& mp = dynamic_cast <const maildirPart&>(p);
extractImpl(os, progress, mp.getBodyParsedOffset(), mp.getBodyParsedLength(),
start, length, peek);
}
void maildirMessage::extractImpl(utility::outputStream& os, utility::progressionListener* progress,
const int start, const int length, const int partialStart, const int partialLength,
const bool /* peek */) const
{
utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
const utility::file::path path = m_folder->getMessageFSPath(m_num);
ref <utility::file> file = fsf->create(path);
ref <utility::fileReader> reader = file->getFileReader();
ref <utility::inputStream> is = reader->getInputStream();
is->skip(start + partialStart);
utility::stream::value_type buffer[8192];
utility::stream::size_type remaining = (partialLength == -1 ? length
: std::min(partialLength, length));
const int total = remaining;
int current = 0;
if (progress)
progress->start(total);
while (!is->eof() && remaining > 0)
{
const utility::stream::size_type read =
is->read(buffer, std::min(remaining, sizeof(buffer)));
remaining -= read;
current += read;
os.write(buffer, read);
if (progress)
progress->progress(current, total);
}
if (progress)
progress->stop(total);
// TODO: mark as read unless 'peek' is set
}
void maildirMessage::fetchPartHeader(part& p)
{
maildirPart& mp = dynamic_cast <maildirPart&>(p);
utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
const utility::file::path path = m_folder->getMessageFSPath(m_num);
ref <utility::file> file = fsf->create(path);
ref <utility::fileReader> reader = file->getFileReader();
ref <utility::inputStream> is = reader->getInputStream();
is->skip(mp.getHeaderParsedOffset());
utility::stream::value_type buffer[1024];
utility::stream::size_type remaining = mp.getHeaderParsedLength();
string contents;
contents.reserve(remaining);
while (!is->eof() && remaining > 0)
{
const utility::stream::size_type read =
is->read(buffer, std::min(remaining, sizeof(buffer)));
remaining -= read;
contents.append(buffer, read);
}
mp.getOrCreateHeader().parse(contents);
}
void maildirMessage::fetch(weak_ref <maildirFolder> folder, const int options)
{
if (m_folder != folder)
throw exceptions::folder_not_found();
utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
const utility::file::path path = folder->getMessageFSPath(m_num);
ref <utility::file> file = fsf->create(path);
if (options & folder::FETCH_FLAGS)
m_flags = maildirUtils::extractFlags(path.getLastComponent());
if (options & folder::FETCH_SIZE)
m_size = file->getLength();
if (options & folder::FETCH_UID)
m_uid = maildirUtils::extractId(path.getLastComponent()).getBuffer();
if (options & (folder::FETCH_ENVELOPE | folder::FETCH_CONTENT_INFO |
folder::FETCH_FULL_HEADER | folder::FETCH_STRUCTURE |
folder::FETCH_IMPORTANCE))
{
string contents;
ref <utility::fileReader> reader = file->getFileReader();
ref <utility::inputStream> is = reader->getInputStream();
// Need whole message contents for structure
if (options & folder::FETCH_STRUCTURE)
{
utility::stream::value_type buffer[16384];
contents.reserve(file->getLength());
while (!is->eof())
{
const utility::stream::size_type read = is->read(buffer, sizeof(buffer));
contents.append(buffer, read);
}
}
// Need only header
else
{
utility::stream::value_type buffer[1024];
contents.reserve(4096);
while (!is->eof())
{
const utility::stream::size_type read = is->read(buffer, sizeof(buffer));
contents.append(buffer, read);
const string::size_type sep1 = contents.rfind("\r\n\r\n");
const string::size_type sep2 = contents.rfind("\n\n");
if (sep1 != string::npos)
{
contents.erase(contents.begin() + sep1 + 4, contents.end());
break;
}
else if (sep2 != string::npos)
{
contents.erase(contents.begin() + sep2 + 2, contents.end());
break;
}
}
}
vmime::message msg;
msg.parse(contents);
// Extract structure
if (options & folder::FETCH_STRUCTURE)
{
m_structure = vmime::create <maildirStructure>(null, msg);
}
// Extract some header fields or whole header
if (options & (folder::FETCH_ENVELOPE |
folder::FETCH_CONTENT_INFO |
folder::FETCH_FULL_HEADER |
folder::FETCH_IMPORTANCE))
{
getOrCreateHeader()->copyFrom(*(msg.getHeader()));
}
}
}
ref <header> maildirMessage::getOrCreateHeader()
{
if (m_header != NULL)
return (m_header);
else
return (m_header = vmime::create <header>());
}
} // maildir
} // net
} // vmime

View File

@ -0,0 +1,250 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/maildir/maildirStore.hpp"
#include "vmime/net/maildir/maildirFolder.hpp"
#include "vmime/utility/smartPtr.hpp"
#include "vmime/exception.hpp"
#include "vmime/platformDependant.hpp"
// Helpers for service properties
#define GET_PROPERTY(type, prop) \
(sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop))
#define HAS_PROPERTY(prop) \
(sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop))
namespace vmime {
namespace net {
namespace maildir {
maildirStore::maildirStore(ref <session> sess, ref <authenticator> auth)
: store(sess, getInfosInstance(), auth), m_connected(false)
{
}
maildirStore::~maildirStore()
{
if (isConnected())
disconnect();
}
const string maildirStore::getProtocolName() const
{
return "maildir";
}
ref <folder> maildirStore::getRootFolder()
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <maildirFolder>(folder::path(),
thisWeakRef().dynamicCast <maildirStore>());
}
ref <folder> maildirStore::getDefaultFolder()
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <maildirFolder>(folder::path::component("inbox"),
thisWeakRef().dynamicCast <maildirStore>());
}
ref <folder> maildirStore::getFolder(const folder::path& path)
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <maildirFolder>(path,
thisWeakRef().dynamicCast <maildirStore>());
}
const bool maildirStore::isValidFolderName(const folder::path::component& name) const
{
if (!platformDependant::getHandler()->getFileSystemFactory()->isValidPathComponent(name))
return false;
const string& buf = name.getBuffer();
// Name cannot start/end with spaces
if (utility::stringUtils::trim(buf) != name.getBuffer())
return false;
// Name cannot start with '.'
const int length = buf.length();
int pos = 0;
while ((pos < length) && (buf[pos] == '.'))
++pos;
return (pos == 0);
}
void maildirStore::connect()
{
if (isConnected())
throw exceptions::already_connected();
// Get root directory
utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
m_fsPath = fsf->stringToPath(GET_PROPERTY(string, PROPERTY_SERVER_ROOTPATH));
ref <utility::file> rootDir = fsf->create(m_fsPath);
// Try to create the root directory if it does not exist
if (!(rootDir->exists() && rootDir->isDirectory()))
{
try
{
rootDir->createDirectory();
}
catch (exceptions::filesystem_exception& e)
{
throw exceptions::connection_error("Cannot create root directory.", e);
}
}
m_connected = true;
}
const bool maildirStore::isConnected() const
{
return (m_connected);
}
void maildirStore::disconnect()
{
for (std::list <maildirFolder*>::iterator it = m_folders.begin() ;
it != m_folders.end() ; ++it)
{
(*it)->onStoreDisconnected();
}
m_folders.clear();
m_connected = false;
}
void maildirStore::noop()
{
// Nothing to do.
}
void maildirStore::registerFolder(maildirFolder* folder)
{
m_folders.push_back(folder);
}
void maildirStore::unregisterFolder(maildirFolder* folder)
{
std::list <maildirFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
if (it != m_folders.end()) m_folders.erase(it);
}
const utility::path& maildirStore::getFileSystemPath() const
{
return (m_fsPath);
}
const int maildirStore::getCapabilities() const
{
return (CAPABILITY_CREATE_FOLDER |
CAPABILITY_RENAME_FOLDER |
CAPABILITY_ADD_MESSAGE |
CAPABILITY_COPY_MESSAGE |
CAPABILITY_DELETE_MESSAGE |
CAPABILITY_PARTIAL_FETCH |
CAPABILITY_MESSAGE_FLAGS |
CAPABILITY_EXTRACT_PART);
}
// Service infos
maildirStore::_infos maildirStore::sm_infos;
const serviceInfos& maildirStore::getInfosInstance()
{
return (sm_infos);
}
const serviceInfos& maildirStore::getInfos() const
{
return (sm_infos);
}
const string maildirStore::_infos::getPropertyPrefix() const
{
return "store.maildir.";
}
const maildirStore::_infos::props& maildirStore::_infos::getProperties() const
{
static props p =
{
property(serviceInfos::property::SERVER_ROOTPATH, serviceInfos::property::FLAG_REQUIRED)
};
return p;
}
const std::vector <serviceInfos::property> maildirStore::_infos::getAvailableProperties() const
{
std::vector <property> list;
const props& p = getProperties();
// Maildir-specific properties
list.push_back(p.PROPERTY_SERVER_ROOTPATH);
return (list);
}
} // maildir
} // net
} // vmime

View File

@ -0,0 +1,208 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/maildir/maildirUtils.hpp"
#include "vmime/net/maildir/maildirStore.hpp"
#include "vmime/utility/random.hpp"
namespace vmime {
namespace net {
namespace maildir {
const vmime::word maildirUtils::TMP_DIR("tmp", vmime::charset(vmime::charsets::US_ASCII)); // ensure reliable delivery (not to be listed)
const vmime::word maildirUtils::CUR_DIR("cur", vmime::charset(vmime::charsets::US_ASCII)); // no longer new messages
const vmime::word maildirUtils::NEW_DIR("new", vmime::charset(vmime::charsets::US_ASCII)); // unread messages
const utility::file::path maildirUtils::getFolderFSPath
(weak_ref <maildirStore> store, const utility::path& folderPath, const FolderFSPathMode mode)
{
// Root path
utility::file::path path(store->getFileSystemPath());
const int count = (mode == FOLDER_PATH_CONTAINER
? folderPath.getSize() : folderPath.getSize() - 1);
// Parent folders
for (int i = 0 ; i < count ; ++i)
{
utility::file::path::component comp(folderPath[i]);
// TODO: may not work with all encodings...
comp.setBuffer("." + comp.getBuffer() + ".directory");
path /= comp;
}
// Last component
if (folderPath.getSize() != 0 &&
mode != FOLDER_PATH_CONTAINER)
{
path /= folderPath.getLastComponent();
switch (mode)
{
case FOLDER_PATH_ROOT: break; // Nothing to do
case FOLDER_PATH_NEW: path /= NEW_DIR; break;
case FOLDER_PATH_CUR: path /= CUR_DIR; break;
case FOLDER_PATH_TMP: path /= TMP_DIR; break;
case FOLDER_PATH_CONTAINER: break; // Can't happen...
}
}
return (path);
}
const bool maildirUtils::isSubfolderDirectory(const utility::file& file)
{
// A directory which name does not start with '.'
// is listed as a sub-folder...
if (file.isDirectory() &&
file.getFullPath().getLastComponent().getBuffer().length() >= 1 &&
file.getFullPath().getLastComponent().getBuffer()[0] != '.')
{
return (true);
}
return (false);
}
const bool maildirUtils::isMessageFile(const utility::file& file)
{
// Ignore files which name begins with '.'
if (file.isFile() &&
file.getFullPath().getLastComponent().getBuffer().length() >= 1 &&
file.getFullPath().getLastComponent().getBuffer()[0] != '.')
{
return (true);
}
return (false);
}
const utility::file::path::component maildirUtils::extractId
(const utility::file::path::component& filename)
{
string::size_type sep = filename.getBuffer().rfind(':');
if (sep == string::npos) return (filename);
return (utility::path::component
(string(filename.getBuffer().begin(), filename.getBuffer().begin() + sep)));
}
const int maildirUtils::extractFlags(const utility::file::path::component& comp)
{
string::size_type sep = comp.getBuffer().rfind(':');
if (sep == string::npos) return (0);
const string flagsString(comp.getBuffer().begin() + sep + 1, comp.getBuffer().end());
const string::size_type count = flagsString.length();
int flags = 0;
for (string::size_type i = 0 ; i < count ; ++i)
{
switch (flagsString[i])
{
case 'R': case 'r': flags |= message::FLAG_REPLIED; break;
case 'S': case 's': flags |= message::FLAG_SEEN; break;
case 'T': case 't': flags |= message::FLAG_DELETED; break;
case 'F': case 'f': flags |= message::FLAG_MARKED; break;
case 'P': case 'p': flags |= message::FLAG_PASSED; break;
}
}
return (flags);
}
const utility::file::path::component maildirUtils::buildFlags(const int flags)
{
string str;
str.reserve(8);
str += "2,";
if (flags & message::FLAG_MARKED) str += "F";
if (flags & message::FLAG_PASSED) str += "P";
if (flags & message::FLAG_REPLIED) str += "R";
if (flags & message::FLAG_SEEN) str += "S";
if (flags & message::FLAG_DELETED) str += "T";
return (utility::file::path::component(str));
}
const utility::file::path::component maildirUtils::buildFilename
(const utility::file::path::component& id, const int flags)
{
return (buildFilename(id, buildFlags(flags)));
}
const utility::file::path::component maildirUtils::buildFilename
(const utility::file::path::component& id, const utility::file::path::component& flags)
{
return (utility::path::component(id.getBuffer() + ":" + flags.getBuffer()));
}
const utility::file::path::component maildirUtils::generateId()
{
std::ostringstream oss;
oss << utility::random::getTime();
oss << ".";
oss << utility::random::getProcess();
oss << ".";
oss << utility::random::getString(6);
return (utility::file::path::component(oss.str()));
}
//
// messageIdComparator
//
maildirUtils::messageIdComparator::messageIdComparator
(const utility::file::path::component& comp)
: m_comp(maildirUtils::extractId(comp))
{
}
const bool maildirUtils::messageIdComparator::operator()
(const utility::file::path::component& other) const
{
return (m_comp == maildirUtils::extractId(other));
}
} // maildir
} // net
} // vmime

46
src/net/message.cpp Normal file
View File

@ -0,0 +1,46 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/message.hpp"
namespace vmime {
namespace net {
const part& part::operator[](const int x) const
{
return (getStructure()[x]);
}
part& part::operator[](const int x)
{
return (getStructure()[x]);
}
const int part::getCount() const
{
return (getStructure().getCount());
}
} // net
} // vmime

826
src/net/pop3/POP3Folder.cpp Normal file
View File

@ -0,0 +1,826 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/pop3/POP3Folder.hpp"
#include "vmime/net/pop3/POP3Store.hpp"
#include "vmime/net/pop3/POP3Message.hpp"
#include "vmime/exception.hpp"
namespace vmime {
namespace net {
namespace pop3 {
POP3Folder::POP3Folder(const folder::path& path, POP3Store* store)
: m_store(store), m_path(path),
m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()),
m_mode(-1), m_open(false)
{
m_store->registerFolder(this);
}
POP3Folder::~POP3Folder()
{
if (m_store)
{
if (m_open)
close(false);
m_store->unregisterFolder(this);
}
else if (m_open)
{
onClose();
}
}
const int POP3Folder::getMode() const
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
return (m_mode);
}
const int POP3Folder::getType()
{
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
if (m_path.isEmpty())
return (TYPE_CONTAINS_FOLDERS);
else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX")
return (TYPE_CONTAINS_MESSAGES);
else
throw exceptions::folder_not_found();
}
const int POP3Folder::getFlags()
{
return (0);
}
const folder::path::component POP3Folder::getName() const
{
return (m_name);
}
const folder::path POP3Folder::getFullPath() const
{
return (m_path);
}
void POP3Folder::open(const int mode, bool failIfModeIsNotAvailable)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
if (m_path.isEmpty())
{
if (mode != MODE_READ_ONLY && failIfModeIsNotAvailable)
throw exceptions::operation_not_supported();
m_open = true;
m_mode = mode;
m_messageCount = 0;
}
else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX")
{
m_store->sendRequest("STAT");
string response;
m_store->readResponse(response, false);
if (!m_store->isSuccessResponse(response))
throw exceptions::command_error("STAT", response);
m_store->stripResponseCode(response, response);
std::istringstream iss(response);
iss >> m_messageCount;
if (iss.fail())
throw exceptions::invalid_response("STAT", response);
m_open = true;
m_mode = mode;
}
else
{
throw exceptions::folder_not_found();
}
}
void POP3Folder::close(const bool expunge)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
if (!isOpen())
throw exceptions::illegal_state("Folder not open");
if (!expunge)
{
m_store->sendRequest("RSET");
string response;
m_store->readResponse(response, false);
}
m_open = false;
m_mode = -1;
onClose();
}
void POP3Folder::onClose()
{
for (MessageMap::iterator it = m_messages.begin() ; it != m_messages.end() ; ++it)
(*it).first->onFolderClosed();
m_messages.clear();
}
void POP3Folder::create(const int /* type */)
{
throw exceptions::operation_not_supported();
}
const bool POP3Folder::exists()
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
return (m_path.isEmpty() || (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX"));
}
const bool POP3Folder::isOpen() const
{
return (m_open);
}
ref <message> POP3Folder::getMessage(const int num)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (num < 1 || num > m_messageCount)
throw exceptions::message_not_found();
return vmime::create <POP3Message>(this, num);
}
std::vector <ref <message> > POP3Folder::getMessages(const int from, const int to)
{
const int to2 = (to == -1 ? m_messageCount : to);
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
else if (to2 < from || from < 1 || to2 < 1 || from > m_messageCount || to2 > m_messageCount)
throw exceptions::message_not_found();
std::vector <ref <message> > v;
for (int i = from ; i <= to2 ; ++i)
v.push_back(vmime::create <POP3Message>(this, i));
return (v);
}
std::vector <ref <message> > POP3Folder::getMessages(const std::vector <int>& nums)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
std::vector <ref <message> > v;
for (std::vector <int>::const_iterator it = nums.begin() ; it != nums.end() ; ++it)
{
if (*it < 1|| *it > m_messageCount)
throw exceptions::message_not_found();
v.push_back(vmime::create <POP3Message>(this, *it));
}
return (v);
}
const int POP3Folder::getMessageCount()
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
return (m_messageCount);
}
ref <folder> POP3Folder::getFolder(const folder::path::component& name)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
return vmime::create <POP3Folder>(m_path / name, m_store);
}
std::vector <ref <folder> > POP3Folder::getFolders(const bool /* recursive */)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
if (m_path.isEmpty())
{
std::vector <ref <folder> > v;
v.push_back(vmime::create <POP3Folder>(folder::path::component("INBOX"), m_store));
return (v);
}
else
{
std::vector <ref <folder> > v;
return (v);
}
}
void POP3Folder::fetchMessages(std::vector <ref <message> >& msg, const int options,
utility::progressionListener* progress)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
const int total = msg.size();
int current = 0;
if (progress)
progress->start(total);
for (std::vector <ref <message> >::iterator it = msg.begin() ;
it != msg.end() ; ++it)
{
(*it).dynamicCast <POP3Message>()->fetch(this, options);
if (progress)
progress->progress(++current, total);
}
if (options & FETCH_SIZE)
{
// Send the "LIST" command
std::ostringstream command;
command << "LIST";
m_store->sendRequest(command.str());
// Get the response
string response;
m_store->readResponse(response, true, NULL);
if (m_store->isSuccessResponse(response))
{
m_store->stripFirstLine(response, response, NULL);
// C: LIST
// S: +OK
// S: 1 47548
// S: 2 12653
// S: .
std::map <int, string> result;
parseMultiListOrUidlResponse(response, result);
for (std::vector <ref <message> >::iterator it = msg.begin() ;
it != msg.end() ; ++it)
{
ref <POP3Message> m = (*it).dynamicCast <POP3Message>();
std::map <int, string>::const_iterator x = result.find(m->m_num);
if (x != result.end())
{
int size = 0;
std::istringstream iss((*x).second);
iss >> size;
m->m_size = size;
}
}
}
}
if (options & FETCH_UID)
{
// Send the "UIDL" command
std::ostringstream command;
command << "UIDL";
m_store->sendRequest(command.str());
// Get the response
string response;
m_store->readResponse(response, true, NULL);
if (m_store->isSuccessResponse(response))
{
m_store->stripFirstLine(response, response, NULL);
// C: UIDL
// S: +OK
// S: 1 whqtswO00WBw418f9t5JxYwZ
// S: 2 QhdPYR:00WBw1Ph7x7
// S: .
std::map <int, string> result;
parseMultiListOrUidlResponse(response, result);
for (std::vector <ref <message> >::iterator it = msg.begin() ;
it != msg.end() ; ++it)
{
ref <POP3Message> m = (*it).dynamicCast <POP3Message>();
std::map <int, string>::const_iterator x = result.find(m->m_num);
if (x != result.end())
m->m_uid = (*x).second;
}
}
}
if (progress)
progress->stop(total);
}
void POP3Folder::fetchMessage(ref <message> msg, const int options)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
msg.dynamicCast <POP3Message>()->fetch(this, options);
if (options & FETCH_SIZE)
{
// Send the "LIST" command
std::ostringstream command;
command << "LIST " << msg->getNumber();
m_store->sendRequest(command.str());
// Get the response
string response;
m_store->readResponse(response, false, NULL);
if (m_store->isSuccessResponse(response))
{
m_store->stripResponseCode(response, response);
// C: LIST 2
// S: +OK 2 4242
string::iterator it = response.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;
if (it != response.end())
{
int size = 0;
std::istringstream iss(string(it, response.end()));
iss >> size;
msg.dynamicCast <POP3Message>()->m_size = size;
}
}
}
if (options & FETCH_UID)
{
// Send the "UIDL" command
std::ostringstream command;
command << "UIDL " << msg->getNumber();
m_store->sendRequest(command.str());
// Get the response
string response;
m_store->readResponse(response, false, NULL);
if (m_store->isSuccessResponse(response))
{
m_store->stripResponseCode(response, response);
// C: UIDL 2
// S: +OK 2 QhdPYR:00WBw1Ph7x7
string::iterator it = response.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;
if (it != response.end())
{
msg.dynamicCast <POP3Message>()->m_uid =
string(it, response.end());
}
}
}
}
const int POP3Folder::getFetchCapabilities() const
{
return (FETCH_ENVELOPE | FETCH_CONTENT_INFO |
FETCH_SIZE | FETCH_FULL_HEADER | FETCH_UID |
FETCH_IMPORTANCE);
}
ref <folder> POP3Folder::getParent()
{
if (m_path.isEmpty())
return NULL;
else
return vmime::create <POP3Folder>(m_path.getParent(), m_store);
}
weak_ref <const store> POP3Folder::getStore() const
{
return (m_store);
}
weak_ref <store> POP3Folder::getStore()
{
return (m_store);
}
void POP3Folder::registerMessage(POP3Message* msg)
{
m_messages.insert(MessageMap::value_type(msg, msg->getNumber()));
}
void POP3Folder::unregisterMessage(POP3Message* msg)
{
m_messages.erase(msg);
}
void POP3Folder::onStoreDisconnected()
{
m_store = NULL;
}
void POP3Folder::deleteMessage(const int num)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
std::ostringstream command;
command << "DELE " << num;
m_store->sendRequest(command.str());
string response;
m_store->readResponse(response, false);
if (!m_store->isSuccessResponse(response))
throw exceptions::command_error("DELE", response);
// Update local flags
for (std::map <POP3Message*, int>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
POP3Message* msg = (*it).first;
if (msg->getNumber() == num)
msg->m_deleted = true;
}
// Notify message flags changed
std::vector <int> nums;
nums.push_back(num);
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, nums);
notifyMessageChanged(event);
}
void POP3Folder::deleteMessages(const int from, const int to)
{
if (from < 1 || (to < from && to != -1))
throw exceptions::invalid_argument();
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
const int to2 = (to == -1 ? m_messageCount : to);
for (int i = from ; i <= to2 ; ++i)
{
std::ostringstream command;
command << "DELE " << i;
m_store->sendRequest(command.str());
string response;
m_store->readResponse(response, false);
if (!m_store->isSuccessResponse(response))
throw exceptions::command_error("DELE", response);
}
// Update local flags
for (std::map <POP3Message*, int>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
POP3Message* msg = (*it).first;
if (msg->getNumber() >= from && msg->getNumber() <= to2)
msg->m_deleted = true;
}
// Notify message flags changed
std::vector <int> nums;
for (int i = from ; i <= to2 ; ++i)
nums.push_back(i);
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, nums);
notifyMessageChanged(event);
}
void POP3Folder::deleteMessages(const std::vector <int>& nums)
{
if (nums.empty())
throw exceptions::invalid_argument();
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
for (std::vector <int>::const_iterator
it = nums.begin() ; it != nums.end() ; ++it)
{
std::ostringstream command;
command << "DELE " << (*it);
m_store->sendRequest(command.str());
string response;
m_store->readResponse(response, false);
if (!m_store->isSuccessResponse(response))
throw exceptions::command_error("DELE", response);
}
// Sort message list
std::vector <int> list;
list.resize(nums.size());
std::copy(nums.begin(), nums.end(), list.begin());
std::sort(list.begin(), list.end());
// Update local flags
for (std::map <POP3Message*, int>::iterator it =
m_messages.begin() ; it != m_messages.end() ; ++it)
{
POP3Message* msg = (*it).first;
if (std::binary_search(list.begin(), list.end(), msg->getNumber()))
msg->m_deleted = true;
}
// Notify message flags changed
events::messageChangedEvent event
(thisRef().dynamicCast <folder>(),
events::messageChangedEvent::TYPE_FLAGS, list);
notifyMessageChanged(event);
}
void POP3Folder::setMessageFlags(const int /* from */, const int /* to */,
const int /* flags */, const int /* mode */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::setMessageFlags(const std::vector <int>& /* nums */,
const int /* flags */, const int /* mode */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::rename(const folder::path& /* newPath */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::addMessage(ref <vmime::message> /* msg */, const int /* flags */,
vmime::datetime* /* date */, utility::progressionListener* /* progress */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::addMessage(utility::inputStream& /* is */, const int /* size */, const int /* flags */,
vmime::datetime* /* date */, utility::progressionListener* /* progress */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::copyMessage(const folder::path& /* dest */, const int /* num */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::copyMessages(const folder::path& /* dest */, const int /* from */, const int /* to */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::copyMessages(const folder::path& /* dest */, const std::vector <int>& /* nums */)
{
throw exceptions::operation_not_supported();
}
void POP3Folder::status(int& count, int& unseen)
{
if (!m_store)
throw exceptions::illegal_state("Store disconnected");
else if (!isOpen())
throw exceptions::illegal_state("Folder not open");
m_store->sendRequest("STAT");
string response;
m_store->readResponse(response, false);
if (!m_store->isSuccessResponse(response))
throw exceptions::command_error("STAT", response);
m_store->stripResponseCode(response, response);
std::istringstream iss(response);
iss >> count;
unseen = count;
// Update local message count
if (m_messageCount != count)
{
const int oldCount = m_messageCount;
m_messageCount = count;
if (count > oldCount)
{
std::vector <int> nums;
nums.reserve(count - oldCount);
for (int i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j)
nums[j] = i;
// Notify message count changed
events::messageCountEvent event
(thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
notifyMessageCount(event);
// Notify folders with the same path
for (std::list <POP3Folder*>::iterator it = m_store->m_folders.begin() ;
it != m_store->m_folders.end() ; ++it)
{
if ((*it) != this && (*it)->getFullPath() == m_path)
{
(*it)->m_messageCount = count;
events::messageCountEvent event
((*it)->thisRef().dynamicCast <folder>(),
events::messageCountEvent::TYPE_ADDED, nums);
(*it)->notifyMessageCount(event);
}
}
}
}
}
void POP3Folder::expunge()
{
// Not supported by POP3 protocol (deleted messages are automatically
// expunged at the end of the session...).
}
void POP3Folder::parseMultiListOrUidlResponse(const string& response, std::map <int, string>& result)
{
std::istringstream iss(response);
std::map <int, string> ids;
string line;
while (std::getline(iss, line))
{
string::iterator it = line.begin();
while (it != line.end() && (*it == ' ' || *it == '\t'))
++it;
if (it != line.end())
{
int number = 0;
while (it != line.end() && (*it >= '0' && *it <= '9'))
{
number = (number * 10) + (*it - '0');
++it;
}
while (it != line.end() && !(*it == ' ' || *it == '\t')) ++it;
while (it != line.end() && (*it == ' ' || *it == '\t')) ++it;
if (it != line.end())
{
result.insert(std::map <int, string>::value_type(number, string(it, line.end())));
}
}
}
}
} // pop3
} // net
} // vmime

View File

@ -0,0 +1,213 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/pop3/POP3Message.hpp"
#include "vmime/net/pop3/POP3Folder.hpp"
#include "vmime/net/pop3/POP3Store.hpp"
#include <sstream>
namespace vmime {
namespace net {
namespace pop3 {
POP3Message::POP3Message(POP3Folder* folder, const int num)
: m_folder(folder), m_num(num), m_size(-1), m_deleted(false)
{
m_folder->registerMessage(this);
}
POP3Message::~POP3Message()
{
if (m_folder)
m_folder->unregisterMessage(this);
}
void POP3Message::onFolderClosed()
{
m_folder = NULL;
}
const int POP3Message::getNumber() const
{
return (m_num);
}
const message::uid POP3Message::getUniqueId() const
{
return (m_uid);
}
const int POP3Message::getSize() const
{
if (m_size == -1)
throw exceptions::unfetched_object();
return (m_size);
}
const bool POP3Message::isExpunged() const
{
return (false);
}
const int POP3Message::getFlags() const
{
int flags = FLAG_RECENT;
if (m_deleted)
flags |= FLAG_DELETED;
return (flags);
}
const structure& POP3Message::getStructure() const
{
throw exceptions::operation_not_supported();
}
structure& POP3Message::getStructure()
{
throw exceptions::operation_not_supported();
}
ref <const header> POP3Message::getHeader() const
{
if (m_header == NULL)
throw exceptions::unfetched_object();
return (m_header);
}
void POP3Message::extract(utility::outputStream& os,
utility::progressionListener* progress, const int start,
const int length, const bool /* peek */) const
{
if (!m_folder)
throw exceptions::illegal_state("Folder closed");
else if (!m_folder->m_store)
throw exceptions::illegal_state("Store disconnected");
if (start != 0 && length != -1)
throw exceptions::partial_fetch_not_supported();
// Emit the "RETR" command
std::ostringstream oss;
oss << "RETR " << m_num;
const_cast <POP3Folder*>(m_folder)->m_store->sendRequest(oss.str());
try
{
POP3Folder::MessageMap::const_iterator it =
m_folder->m_messages.find(const_cast <POP3Message*>(this));
const int totalSize = (it != m_folder->m_messages.end())
? (*it).second : 0;
const_cast <POP3Folder*>(m_folder)->m_store->
readResponse(os, progress, totalSize);
}
catch (exceptions::command_error& e)
{
throw exceptions::command_error("RETR", e.response());
}
}
void POP3Message::extractPart
(const part& /* p */, utility::outputStream& /* os */,
utility::progressionListener* /* progress */,
const int /* start */, const int /* length */,
const bool /* peek */) const
{
throw exceptions::operation_not_supported();
}
void POP3Message::fetchPartHeader(part& /* p */)
{
throw exceptions::operation_not_supported();
}
void POP3Message::fetch(POP3Folder* folder, const int options)
{
if (m_folder != folder)
throw exceptions::folder_not_found();
// FETCH_STRUCTURE and FETCH_FLAGS are not supported by POP3.
if (options & (folder::FETCH_STRUCTURE | folder::FETCH_FLAGS))
throw exceptions::operation_not_supported();
// Check for the real need to fetch the full header
static const int optionsRequiringHeader =
folder::FETCH_ENVELOPE | folder::FETCH_CONTENT_INFO |
folder::FETCH_FULL_HEADER | folder::FETCH_IMPORTANCE;
if (!(options & optionsRequiringHeader))
return;
// No need to differenciate between FETCH_ENVELOPE,
// FETCH_CONTENT_INFO, ... since POP3 only permits to
// retrieve the whole header and not fields in particular.
// Emit the "TOP" command
std::ostringstream oss;
oss << "TOP " << m_num << " 0";
m_folder->m_store->sendRequest(oss.str());
try
{
string buffer;
m_folder->m_store->readResponse(buffer, true);
m_header = vmime::create <header>();
m_header->parse(buffer);
}
catch (exceptions::command_error& e)
{
throw exceptions::command_error("TOP", e.response());
}
}
void POP3Message::setFlags(const int /* flags */, const int /* mode */)
{
throw exceptions::operation_not_supported();
}
} // pop3
} // net
} // vmime

630
src/net/pop3/POP3Store.cpp Normal file
View File

@ -0,0 +1,630 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/pop3/POP3Store.hpp"
#include "vmime/net/pop3/POP3Folder.hpp"
#include "vmime/exception.hpp"
#include "vmime/platformDependant.hpp"
#include "vmime/messageId.hpp"
#include "vmime/utility/md5.hpp"
#include "vmime/utility/filteredStream.hpp"
#include <algorithm>
// Helpers for service properties
#define GET_PROPERTY(type, prop) \
(sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop))
#define HAS_PROPERTY(prop) \
(sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop))
namespace vmime {
namespace net {
namespace pop3 {
POP3Store::POP3Store(ref <session> sess, ref <authenticator> auth)
: store(sess, getInfosInstance(), auth), m_socket(NULL),
m_authentified(false), m_timeoutHandler(NULL)
{
}
POP3Store::~POP3Store()
{
if (isConnected())
disconnect();
else if (m_socket)
internalDisconnect();
}
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")), this);
}
ref <folder> POP3Store::getRootFolder()
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <POP3Folder>(folder::path(), this);
}
ref <folder> POP3Store::getFolder(const folder::path& path)
{
if (!isConnected())
throw exceptions::illegal_state("Not connected");
return vmime::create <POP3Folder>(path, this);
}
const 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 (HAS_PROPERTY(PROPERTY_TIMEOUT_FACTORY))
{
timeoutHandlerFactory* tof = platformDependant::getHandler()->
getTimeoutHandlerFactory(GET_PROPERTY(string, PROPERTY_TIMEOUT_FACTORY));
m_timeoutHandler = tof->create();
}
// Create and connect the socket
socketFactory* sf = platformDependant::getHandler()->
getSocketFactory(GET_PROPERTY(string, PROPERTY_SERVER_SOCKETFACTORY));
m_socket = sf->create();
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))
{
bool authentified = false;
const authenticationInfos auth = getAuthenticator()->requestAuthInfos();
// Secured authentication with APOP (if requested and if available)
//
// eg: C: APOP vincent <digest>
// --- S: +OK vincent is a valid mailbox
messageId mid(response);
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP))
{
if (mid.getLeft().length() && mid.getRight().length())
{
// <digest> is the result of MD5 applied to "<message-id>password"
sendRequest("APOP " + auth.getUsername() + " "
+ utility::md5(mid.generate() + auth.getPassword()).hex());
readResponse(response, false);
if (isSuccessResponse(response))
{
authentified = true;
}
else
{
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
{
internalDisconnect();
throw exceptions::authentication_error(response);
}
}
}
else
{
// APOP not supported
if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK))
{
// Can't fallback on basic authentification
internalDisconnect();
throw exceptions::unsupported_option();
}
}
}
if (!authentified)
{
// 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 " + auth.getUsername());
readResponse(response, false);
if (isSuccessResponse(response))
{
sendRequest("PASS " + auth.getPassword());
readResponse(response, false);
if (!isSuccessResponse(response))
{
internalDisconnect();
throw exceptions::authentication_error(response);
}
}
else
{
internalDisconnect();
throw exceptions::authentication_error(response);
}
}
}
else
{
internalDisconnect();
throw exceptions::connection_greeting_error(response);
}
m_authentified = true;
}
const bool POP3Store::isConnected() const
{
return (m_socket && m_socket->isConnected() && m_authentified);
}
void POP3Store::disconnect()
{
if (!isConnected())
throw exceptions::not_connected();
internalDisconnect();
}
void POP3Store::internalDisconnect()
{
for (std::list <POP3Folder*>::iterator it = m_folders.begin() ;
it != m_folders.end() ; ++it)
{
(*it)->onStoreDisconnected();
}
m_folders.clear();
sendRequest("QUIT");
m_socket->disconnect();
m_socket = NULL;
m_timeoutHandler = NULL;
m_authentified = false;
}
void POP3Store::noop()
{
m_socket->send("NOOP");
string response;
readResponse(response, false);
if (!isSuccessResponse(response))
throw exceptions::command_error("NOOP", response);
}
const bool POP3Store::isSuccessResponse(const string& buffer)
{
static const string OK("+OK");
return (buffer.length() >= 3 &&
std::equal(buffer.begin(), buffer.begin() + 3, OK.begin()));
}
const 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);
}
}
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)
m_socket->send(buffer + "\r\n");
else
m_socket->send(buffer);
}
void POP3Store::readResponse(string& buffer, const bool multiLine,
utility::progressionListener* progress)
{
bool foundTerminator = false;
int 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();
}
// Receive data from the socket
string receiveBuffer;
m_socket->receive(receiveBuffer);
if (receiveBuffer.empty()) // buffer is empty
{
platformDependant::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 = (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 progression
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::progressionListener* progress, const int predictedSize)
{
int 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
{
platformDependant::getHandler()->wait();
continue;
}
// We have received data: reset the time-out counter
if (m_timeoutHandler)
m_timeoutHandler->resetTimeOut();
// If we don't have extracted the response code yet
if (!codeDone)
{
temp += string(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);
current += read;
// Notify progression
if (progress)
{
total = std::max(total, current);
progress->progress(current, total);
}
}
}
if (progress)
progress->stop(total);
}
const 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);
}
const 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);
}
void POP3Store::unregisterFolder(POP3Folder* folder)
{
std::list <POP3Folder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
if (it != m_folders.end()) m_folders.erase(it);
}
const int POP3Store::getCapabilities() const
{
return (CAPABILITY_DELETE_MESSAGE);
}
// Service infos
POP3Store::_infos POP3Store::sm_infos;
const serviceInfos& POP3Store::getInfosInstance()
{
return (sm_infos);
}
const serviceInfos& POP3Store::getInfos() const
{
return (sm_infos);
}
const string POP3Store::_infos::getPropertyPrefix() const
{
return "store.pop3.";
}
const POP3Store::_infos::props& POP3Store::_infos::getProperties() const
{
static props p =
{
// POP3-specific options
property("options.apop", serviceInfos::property::TYPE_BOOL, "false"),
property("options.apop.fallback", serviceInfos::property::TYPE_BOOL, "false"),
// Common properties
property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
property(serviceInfos::property::SERVER_PORT, "110"),
property(serviceInfos::property::SERVER_SOCKETFACTORY),
property(serviceInfos::property::TIMEOUT_FACTORY)
};
return p;
}
const std::vector <serviceInfos::property> POP3Store::_infos::getAvailableProperties() const
{
std::vector <property> list;
const props& p = getProperties();
// POP3-specific options
list.push_back(p.PROPERTY_OPTIONS_APOP);
list.push_back(p.PROPERTY_OPTIONS_APOP_FALLBACK);
// Common properties
list.push_back(p.PROPERTY_AUTH_USERNAME);
list.push_back(p.PROPERTY_AUTH_PASSWORD);
list.push_back(p.PROPERTY_SERVER_ADDRESS);
list.push_back(p.PROPERTY_SERVER_PORT);
list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY);
list.push_back(p.PROPERTY_TIMEOUT_FACTORY);
return (list);
}
} // pop3
} // net
} // vmime

View File

@ -0,0 +1,222 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/sendmail/sendmailTransport.hpp"
#include "vmime/exception.hpp"
#include "vmime/platformDependant.hpp"
#include "vmime/message.hpp"
#include "vmime/mailboxList.hpp"
#include "vmime/utility/filteredStream.hpp"
#include "vmime/utility/childProcess.hpp"
#include "vmime/utility/smartPtr.hpp"
#include "vmime/config.hpp"
// Helpers for service properties
#define GET_PROPERTY(type, prop) \
(sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop))
#define HAS_PROPERTY(prop) \
(sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop))
#if VMIME_BUILTIN_PLATFORM_POSIX
namespace vmime {
namespace net {
namespace sendmail {
sendmailTransport::sendmailTransport(ref <session> sess, ref <authenticator> auth)
: transport(sess, getInfosInstance(), auth), m_connected(false)
{
}
sendmailTransport::~sendmailTransport()
{
if (isConnected())
disconnect();
}
const string sendmailTransport::getProtocolName() const
{
return "sendmail";
}
void sendmailTransport::connect()
{
if (isConnected())
throw exceptions::already_connected();
// Use the specified path for 'sendmail' or a default one if no path is specified
m_sendmailPath = GET_PROPERTY(string, PROPERTY_BINPATH);
m_connected = true;
}
const bool sendmailTransport::isConnected() const
{
return (m_connected);
}
void sendmailTransport::disconnect()
{
if (!isConnected())
throw exceptions::not_connected();
internalDisconnect();
}
void sendmailTransport::internalDisconnect()
{
m_connected = false;
}
void sendmailTransport::noop()
{
// Do nothing
}
void sendmailTransport::send
(const mailbox& expeditor, const mailboxList& recipients,
utility::inputStream& is, const utility::stream::size_type size,
utility::progressionListener* progress)
{
// If no recipient/expeditor was found, throw an exception
if (recipients.isEmpty())
throw exceptions::no_recipient();
else if (expeditor.isEmpty())
throw exceptions::no_expeditor();
// Construct the argument list
std::vector <string> args;
args.push_back("-i");
args.push_back("-f");
args.push_back(expeditor.getEmail());
args.push_back("--");
for (int i = 0 ; i < recipients.getMailboxCount() ; ++i)
args.push_back(recipients.getMailboxAt(i)->getEmail());
// Call sendmail
try
{
internalSend(args, is, size, progress);
}
catch (vmime::exception& e)
{
throw exceptions::command_error("SEND", "", "sendmail failed", e);
}
}
void sendmailTransport::internalSend
(const std::vector <string> args, utility::inputStream& is,
const utility::stream::size_type size, utility::progressionListener* progress)
{
const utility::file::path path = vmime::platformDependant::getHandler()->
getFileSystemFactory()->stringToPath(m_sendmailPath);
ref <utility::childProcess> proc =
vmime::platformDependant::getHandler()->
getChildProcessFactory()->create(path);
proc->start(args, utility::childProcess::FLAG_REDIRECT_STDIN);
// Copy message data from input stream to output pipe
utility::outputStream& os = *(proc->getStdIn());
// Workaround for lame sendmail implementations that
// can't handle CRLF eoln sequences: we transform CRLF
// sequences into LF characters.
utility::CRLFToLFFilteredOutputStream fos(os);
// TODO: remove 'Bcc:' field from message header
utility::bufferedStreamCopy(is, fos, size, progress);
// Wait for sendmail to exit
proc->waitForFinish();
}
// Service infos
sendmailTransport::_infos sendmailTransport::sm_infos;
const serviceInfos& sendmailTransport::getInfosInstance()
{
return (sm_infos);
}
const serviceInfos& sendmailTransport::getInfos() const
{
return (sm_infos);
}
const string sendmailTransport::_infos::getPropertyPrefix() const
{
return "transport.sendmail.";
}
const sendmailTransport::_infos::props& sendmailTransport::_infos::getProperties() const
{
static props p =
{
// Path to sendmail (override default)
property("binpath", serviceInfos::property::TYPE_STRING, string(VMIME_SENDMAIL_PATH))
};
return p;
}
const std::vector <serviceInfos::property> sendmailTransport::_infos::getAvailableProperties() const
{
std::vector <property> list;
const props& p = getProperties();
list.push_back(p.PROPERTY_BINPATH);
return (list);
}
} // sendmail
} // net
} // vmime
#endif // VMIME_BUILTIN_PLATFORM_POSIX

70
src/net/service.cpp Normal file
View File

@ -0,0 +1,70 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/service.hpp"
#include "vmime/net/defaultAuthenticator.hpp"
namespace vmime {
namespace net {
service::service(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth)
: m_session(sess), m_auth(auth)
{
if (!auth)
{
m_auth = vmime::create <defaultAuthenticator>
(sess, infos.getPropertyPrefix());
}
}
service::~service()
{
}
ref <const session> service::getSession() const
{
return (m_session);
}
ref <session> service::getSession()
{
return (m_session);
}
ref <const authenticator> service::getAuthenticator() const
{
return (m_auth);
}
ref <authenticator> service::getAuthenticator()
{
return (m_auth);
}
} // net
} // vmime

124
src/net/serviceFactory.cpp Normal file
View File

@ -0,0 +1,124 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/serviceFactory.hpp"
#include "vmime/net/service.hpp"
#include "vmime/exception.hpp"
#include "vmime/config.hpp"
#include "src/net/builtinServices.inl"
namespace vmime {
namespace net {
serviceFactory::serviceFactory()
{
}
serviceFactory::~serviceFactory()
{
}
serviceFactory* serviceFactory::getInstance()
{
static serviceFactory instance;
return (&instance);
}
ref <service> serviceFactory::create
(ref <session> sess, const string& protocol, ref <authenticator> auth)
{
return (getServiceByProtocol(protocol)->create(sess, auth));
}
ref <service> serviceFactory::create
(ref <session> sess, const utility::url& u, ref <authenticator> auth)
{
ref <service> serv = create(sess, u.getProtocol(), auth);
sess->getProperties()[serv->getInfos().getPropertyPrefix() + "server.address"] = u.getHost();
if (u.getPort() != utility::url::UNSPECIFIED_PORT)
sess->getProperties()[serv->getInfos().getPropertyPrefix() + "server.port"] = u.getPort();
// Path portion of the URL is used to point a specific folder (empty = root).
// In maildir, this is used to point to the root of the message repository.
if (!u.getPath().empty())
sess->getProperties()[serv->getInfos().getPropertyPrefix() + "server.rootpath"] = u.getPath();
if (!u.getUsername().empty())
{
sess->getProperties()[serv->getInfos().getPropertyPrefix() + "auth.username"] = u.getUsername();
sess->getProperties()[serv->getInfos().getPropertyPrefix() + "auth.password"] = u.getPassword();
}
return (serv);
}
ref <const serviceFactory::registeredService> serviceFactory::getServiceByProtocol(const string& protocol) const
{
const string name(utility::stringUtils::toLower(protocol));
for (std::vector <ref <registeredService> >::const_iterator it = m_services.begin() ;
it != m_services.end() ; ++it)
{
if ((*it)->getName() == name)
return (*it);
}
throw exceptions::no_service_available(name);
}
const int serviceFactory::getServiceCount() const
{
return (m_services.size());
}
ref <const serviceFactory::registeredService> serviceFactory::getServiceAt(const int pos) const
{
return (m_services[pos]);
}
const std::vector <ref <const serviceFactory::registeredService> > serviceFactory::getServiceList() const
{
std::vector <ref <const registeredService> > res;
for (std::vector <ref <registeredService> >::const_iterator it = m_services.begin() ;
it != m_services.end() ; ++it)
{
res.push_back(*it);
}
return (res);
}
} // net
} // vmime

150
src/net/serviceInfos.cpp Normal file
View File

@ -0,0 +1,150 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/serviceInfos.hpp"
namespace vmime {
namespace net {
// Common properties
const serviceInfos::property serviceInfos::property::SERVER_ADDRESS
("server.address", serviceInfos::property::TYPE_STRING);
const serviceInfos::property serviceInfos::property::SERVER_PORT
("server.port", serviceInfos::property::TYPE_INTEGER);
const serviceInfos::property serviceInfos::property::SERVER_ROOTPATH
("server.rootpath", serviceInfos::property::TYPE_STRING);
const serviceInfos::property serviceInfos::property::SERVER_SOCKETFACTORY
("server.socket-factory", serviceInfos::property::TYPE_STRING, "default");
const serviceInfos::property serviceInfos::property::AUTH_USERNAME
("auth.username", serviceInfos::property::TYPE_STRING);
const serviceInfos::property serviceInfos::property::AUTH_PASSWORD
("auth.password", serviceInfos::property::TYPE_STRING);
const serviceInfos::property serviceInfos::property::TIMEOUT_FACTORY
("timeout.factory", serviceInfos::property::TYPE_STRING);
// serviceInfos
serviceInfos::serviceInfos()
{
}
serviceInfos::serviceInfos(const serviceInfos&)
{
}
serviceInfos& serviceInfos::operator=(const serviceInfos&)
{
return (*this);
}
serviceInfos::~serviceInfos()
{
}
const bool serviceInfos::hasProperty(ref <session> s, const property& p) const
{
return s->getProperties().hasProperty(getPropertyPrefix() + p.getName());
}
// serviceInfos::property
serviceInfos::property::property
(const string& name, const Types type,
const string& defaultValue, const int flags)
: m_name(name), m_defaultValue(defaultValue),
m_type(type), m_flags(flags)
{
}
serviceInfos::property::property
(const property& p, const int addFlags, const int removeFlags)
{
m_name = p.m_name;
m_type = p.m_type;
m_defaultValue = p.m_defaultValue;
m_flags = (p.m_flags | addFlags) & ~removeFlags;
}
serviceInfos::property::property
(const property& p, const string& newDefaultValue,
const int addFlags, const int removeFlags)
{
m_name = p.m_name;
m_type = p.m_type;
m_defaultValue = newDefaultValue;
m_flags = (p.m_flags | addFlags) & ~removeFlags;
}
serviceInfos::property& serviceInfos::property::operator=(const property& p)
{
m_name = p.m_name;
m_type = p.m_type;
m_defaultValue = p.m_defaultValue;
m_flags = p.m_flags;
return (*this);
}
const string& serviceInfos::property::getName() const
{
return (m_name);
}
const string& serviceInfos::property::getDefaultValue() const
{
return (m_defaultValue);
}
const serviceInfos::property::Types serviceInfos::property::getType() const
{
return (m_type);
}
const int serviceInfos::property::getFlags() const
{
return (m_flags);
}
} // net
} // vmime

126
src/net/session.cpp Normal file
View File

@ -0,0 +1,126 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/session.hpp"
#include "vmime/net/serviceFactory.hpp"
#include "vmime/net/store.hpp"
#include "vmime/net/transport.hpp"
namespace vmime {
namespace net {
session::session()
{
}
session::session(const session& sess)
: object(), m_props(sess.m_props)
{
}
session::session(const propertySet& props)
: m_props(props)
{
}
session::~session()
{
}
ref <transport> session::getTransport(ref <authenticator> auth)
{
return (getTransport(m_props["transport.protocol"], auth));
}
ref <transport> session::getTransport(const string& protocol, ref <authenticator> auth)
{
ref <session> sess = thisRef().dynamicCast <session>();
ref <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
if (sv->getType() != service::TYPE_TRANSPORT)
throw exceptions::no_service_available();
return sv.staticCast <transport>();
}
ref <transport> session::getTransport(const utility::url& url, ref <authenticator> auth)
{
ref <session> sess = thisRef().dynamicCast <session>();
ref <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
if (sv->getType() != service::TYPE_TRANSPORT)
throw exceptions::no_service_available();
return sv.staticCast <transport>();
}
ref <store> session::getStore(ref <authenticator> auth)
{
return (getStore(m_props["store.protocol"], auth));
}
ref <store> session::getStore(const string& protocol, ref <authenticator> auth)
{
ref <session> sess = thisRef().dynamicCast <session>();
ref <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
if (sv->getType() != service::TYPE_STORE)
throw exceptions::no_service_available();
return sv.staticCast <store>();
}
ref <store> session::getStore(const utility::url& url, ref <authenticator> auth)
{
ref <session> sess = thisRef().dynamicCast <session>();
ref <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
if (sv->getType() != service::TYPE_STORE)
throw exceptions::no_service_available();
return sv.staticCast <store>();
}
const propertySet& session::getProperties() const
{
return (m_props);
}
propertySet& session::getProperties()
{
return (m_props);
}
} // net
} // vmime

View File

@ -0,0 +1,69 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/simpleAuthenticator.hpp"
namespace vmime {
namespace net {
simpleAuthenticator::simpleAuthenticator()
{
}
simpleAuthenticator::simpleAuthenticator(const string& username, const string& password)
: m_username(username), m_password(password)
{
}
const authenticationInfos simpleAuthenticator::getAuthInfos() const
{
return (authenticationInfos(m_username, m_password));
}
const string& simpleAuthenticator::getUsername() const
{
return (m_username);
}
void simpleAuthenticator::setUsername(const string& username)
{
m_username = username;
}
const string& simpleAuthenticator::getPassword() const
{
return (m_password);
}
void simpleAuthenticator::setPassword(const string& password)
{
m_password = password;
}
} // net
} // vmime

View File

@ -0,0 +1,503 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/smtp/SMTPTransport.hpp"
#include "vmime/exception.hpp"
#include "vmime/platformDependant.hpp"
#include "vmime/encoderB64.hpp"
#include "vmime/mailboxList.hpp"
#include "vmime/net/authHelper.hpp"
#include "vmime/utility/filteredStream.hpp"
// Helpers for service properties
#define GET_PROPERTY(type, prop) \
(sm_infos.getPropertyValue <type>(getSession(), sm_infos.getProperties().prop))
#define HAS_PROPERTY(prop) \
(sm_infos.hasProperty(getSession(), sm_infos.getProperties().prop))
namespace vmime {
namespace net {
namespace smtp {
SMTPTransport::SMTPTransport(ref <session> sess, ref <authenticator> auth)
: transport(sess, getInfosInstance(), auth), m_socket(NULL),
m_authentified(false), m_extendedSMTP(false), m_timeoutHandler(NULL)
{
}
SMTPTransport::~SMTPTransport()
{
if (isConnected())
disconnect();
else if (m_socket)
internalDisconnect();
}
const string SMTPTransport::getProtocolName() const
{
return "smtp";
}
void SMTPTransport::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 (HAS_PROPERTY(PROPERTY_TIMEOUT_FACTORY))
{
timeoutHandlerFactory* tof = platformDependant::getHandler()->
getTimeoutHandlerFactory(GET_PROPERTY(string, PROPERTY_TIMEOUT_FACTORY));
m_timeoutHandler = tof->create();
}
// Create and connect the socket
socketFactory* sf = platformDependant::getHandler()->
getSocketFactory(GET_PROPERTY(string, PROPERTY_SERVER_SOCKETFACTORY));
m_socket = sf->create();
m_socket->connect(address, port);
// Connection
//
// eg: C: <connection to server>
// --- S: 220 smtp.domain.com Service ready
string response;
readResponse(response);
if (responseCode(response) != 220)
{
internalDisconnect();
throw exceptions::connection_greeting_error(response);
}
// Identification
// First, try Extended SMTP (ESMTP)
//
// eg: C: EHLO thismachine.ourdomain.com
// S: 250 OK
sendRequest("EHLO " + platformDependant::getHandler()->getHostName());
readResponse(response);
if (responseCode(response) != 250)
{
// Next, try "Basic" SMTP
//
// eg: C: HELO thismachine.ourdomain.com
// S: 250 OK
sendRequest("HELO " + platformDependant::getHandler()->getHostName());
readResponse(response);
if (responseCode(response) != 250)
{
internalDisconnect();
throw exceptions::connection_greeting_error(response);
}
m_extendedSMTP = false;
}
else
{
m_extendedSMTP = true;
}
// Authentication
if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH))
{
if (!m_extendedSMTP)
{
internalDisconnect();
throw exceptions::command_error("AUTH", "ESMTP not supported.");
}
const authenticationInfos auth = getAuthenticator()->requestAuthInfos();
bool authentified = false;
enum AuthMethods
{
First = 0,
CRAM_MD5 = First,
// TODO: more authentication methods...
End
};
for (int currentMethod = First ; !authentified ; ++currentMethod)
{
switch (currentMethod)
{
case CRAM_MD5:
{
sendRequest("AUTH CRAM-MD5");
readResponse(response);
if (responseCode(response) == 334)
{
encoderB64 base64;
string challengeB64 = responseText(response);
string challenge, challengeHex;
{
utility::inputStreamStringAdapter in(challengeB64);
utility::outputStreamStringAdapter out(challenge);
base64.decode(in, out);
}
hmac_md5(challenge, auth.getPassword(), challengeHex);
string decoded = auth.getUsername() + " " + challengeHex;
string encoded;
{
utility::inputStreamStringAdapter in(decoded);
utility::outputStreamStringAdapter out(encoded);
base64.encode(in, out);
}
sendRequest(encoded);
readResponse(response);
if (responseCode(response) == 235)
{
authentified = true;
}
else
{
internalDisconnect();
throw exceptions::authentication_error(response);
}
}
break;
}
case End:
{
// All authentication methods have been tried and
// the server does not understand any.
throw exceptions::authentication_error(response);
}
}
}
}
m_authentified = true;
}
const bool SMTPTransport::isConnected() const
{
return (m_socket && m_socket->isConnected() && m_authentified);
}
void SMTPTransport::disconnect()
{
if (!isConnected())
throw exceptions::not_connected();
internalDisconnect();
}
void SMTPTransport::internalDisconnect()
{
sendRequest("QUIT");
m_socket->disconnect();
m_socket = NULL;
m_timeoutHandler = NULL;
m_authentified = false;
m_extendedSMTP = false;
}
void SMTPTransport::noop()
{
m_socket->send("NOOP");
string response;
readResponse(response);
if (responseCode(response) != 250)
throw exceptions::command_error("NOOP", response);
}
void SMTPTransport::send(const mailbox& expeditor, const mailboxList& recipients,
utility::inputStream& is, const utility::stream::size_type size,
utility::progressionListener* progress)
{
// If no recipient/expeditor was found, throw an exception
if (recipients.isEmpty())
throw exceptions::no_recipient();
else if (expeditor.isEmpty())
throw exceptions::no_expeditor();
// Emit the "MAIL" command
string response;
sendRequest("MAIL FROM: <" + expeditor.getEmail() + ">");
readResponse(response);
if (responseCode(response) != 250)
{
internalDisconnect();
throw exceptions::command_error("MAIL", response);
}
// Emit a "RCPT TO" command for each recipient
for (int i = 0 ; i < recipients.getMailboxCount() ; ++i)
{
const mailbox& mbox = *recipients.getMailboxAt(i);
sendRequest("RCPT TO: <" + mbox.getEmail() + ">");
readResponse(response);
if (responseCode(response) != 250)
{
internalDisconnect();
throw exceptions::command_error("RCPT TO", response);
}
}
// Send the message data
sendRequest("DATA");
readResponse(response);
if (responseCode(response) != 354)
{
internalDisconnect();
throw exceptions::command_error("DATA", response);
}
// Stream copy with "\n." to "\n.." transformation
utility::outputStreamSocketAdapter sos(*m_socket);
utility::dotFilteredOutputStream fos(sos);
utility::bufferedStreamCopy(is, fos, size, progress);
// Send end-of-data delimiter
m_socket->sendRaw("\r\n.\r\n", 5);
readResponse(response);
if (responseCode(response) != 250)
{
internalDisconnect();
throw exceptions::command_error("DATA", response);
}
}
void SMTPTransport::sendRequest(const string& buffer, const bool end)
{
m_socket->send(buffer);
if (end) m_socket->send("\r\n");
}
const int SMTPTransport::responseCode(const string& response)
{
int code = 0;
if (response.length() >= 3)
{
code = (response[0] - '0') * 100
+ (response[1] - '0') * 10
+ (response[2] - '0');
}
return (code);
}
const string SMTPTransport::responseText(const string& response)
{
string text;
std::istringstream iss(response);
std::string line;
while (std::getline(iss, line))
{
if (line.length() >= 4)
text += line.substr(4);
else
text += line;
text += "\n";
}
return (text);
}
void SMTPTransport::readResponse(string& buffer)
{
bool foundTerminator = false;
buffer.clear();
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();
}
// Receive data from the socket
string receiveBuffer;
m_socket->receive(receiveBuffer);
if (receiveBuffer.empty()) // buffer is empty
{
platformDependant::getHandler()->wait();
continue;
}
// We have received data: reset the time-out counter
if (m_timeoutHandler)
m_timeoutHandler->resetTimeOut();
// Append the data to the response buffer
buffer += receiveBuffer;
// Check for terminator string (and strip it if present)
if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
{
string::size_type p = buffer.length() - 2;
bool end = false;
for ( ; !end ; --p)
{
if (p == 0 || buffer[p] == '\n')
{
end = true;
if (p + 4 < buffer.length())
foundTerminator = true;
}
}
}
}
// Remove [CR]LF at the end of the response
if (buffer.length() >= 2 && buffer[buffer.length() - 1] == '\n')
{
if (buffer[buffer.length() - 2] == '\r')
buffer.resize(buffer.length() - 2);
else
buffer.resize(buffer.length() - 1);
}
}
// Service infos
SMTPTransport::_infos SMTPTransport::sm_infos;
const serviceInfos& SMTPTransport::getInfosInstance()
{
return (sm_infos);
}
const serviceInfos& SMTPTransport::getInfos() const
{
return (sm_infos);
}
const string SMTPTransport::_infos::getPropertyPrefix() const
{
return "transport.smtp.";
}
const SMTPTransport::_infos::props& SMTPTransport::_infos::getProperties() const
{
static props p =
{
// SMTP-specific options
property("options.need-authentication", serviceInfos::property::TYPE_BOOL, "false"),
// Common properties
property(serviceInfos::property::AUTH_USERNAME),
property(serviceInfos::property::AUTH_PASSWORD),
property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
property(serviceInfos::property::SERVER_PORT, "25"),
property(serviceInfos::property::SERVER_SOCKETFACTORY),
property(serviceInfos::property::TIMEOUT_FACTORY)
};
return p;
}
const std::vector <serviceInfos::property> SMTPTransport::_infos::getAvailableProperties() const
{
std::vector <property> list;
const props& p = getProperties();
// SMTP-specific options
list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH);
// Common properties
list.push_back(p.PROPERTY_AUTH_USERNAME);
list.push_back(p.PROPERTY_AUTH_PASSWORD);
list.push_back(p.PROPERTY_SERVER_ADDRESS);
list.push_back(p.PROPERTY_SERVER_PORT);
list.push_back(p.PROPERTY_SERVER_SOCKETFACTORY);
list.push_back(p.PROPERTY_TIMEOUT_FACTORY);
return (list);
}
} // smtp
} // net
} // vmime

116
src/net/transport.cpp Normal file
View File

@ -0,0 +1,116 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include "vmime/net/transport.hpp"
#include "vmime/utility/stream.hpp"
#include "vmime/mailboxList.hpp"
#include "vmime/message.hpp"
namespace vmime {
namespace net {
transport::transport(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth)
: service(sess, infos, auth)
{
}
static void extractMailboxes
(mailboxList& recipients, const addressList& list)
{
for (int i = 0 ; i < list.getAddressCount() ; ++i)
{
ref <mailbox> mbox = list.getAddressAt(i)->clone().dynamicCast <mailbox>();
if (mbox != NULL)
recipients.appendMailbox(mbox);
}
}
void transport::send(ref <vmime::message> msg, utility::progressionListener* progress)
{
// Extract expeditor
mailbox expeditor;
try
{
const mailboxField& from = dynamic_cast <const mailboxField&>
(*msg->getHeader()->findField(fields::FROM));
expeditor = from.getValue();
}
catch (exceptions::no_such_field&)
{
throw exceptions::no_expeditor();
}
// Extract recipients
mailboxList recipients;
try
{
const addressListField& to = dynamic_cast <const addressListField&>
(*msg->getHeader()->findField(fields::TO));
extractMailboxes(recipients, to.getValue());
}
catch (exceptions::no_such_field&) { }
try
{
const addressListField& cc = dynamic_cast <const addressListField&>
(*msg->getHeader()->findField(fields::CC));
extractMailboxes(recipients, cc.getValue());
}
catch (exceptions::no_such_field&) { }
try
{
const addressListField& bcc = dynamic_cast <const addressListField&>
(*msg->getHeader()->findField(fields::BCC));
extractMailboxes(recipients, bcc.getValue());
}
catch (exceptions::no_such_field&) { }
// Generate the message, "stream" it and delegate the sending
// to the generic send() function.
std::ostringstream oss;
utility::outputStreamAdapter ossAdapter(oss);
msg->generate(ossAdapter);
const string& str(oss.str());
utility::inputStreamStringAdapter isAdapter(str);
send(expeditor, recipients, isAdapter, str.length(), progress);
}
const transport::Type transport::getType() const
{
return (TYPE_TRANSPORT);
}
} // net
} // vmime

View File

@ -166,14 +166,14 @@ const unsigned int posixHandler::getProcessId() const
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
vmime::messaging::socketFactory* posixHandler::getSocketFactory vmime::net::socketFactory* posixHandler::getSocketFactory
(const vmime::string& /* name */) const (const vmime::string& /* name */) const
{ {
return (m_socketFactory); return (m_socketFactory);
} }
vmime::messaging::timeoutHandlerFactory* posixHandler::getTimeoutHandlerFactory vmime::net::timeoutHandlerFactory* posixHandler::getTimeoutHandlerFactory
(const vmime::string& /* name */) const (const vmime::string& /* name */) const
{ {
// Not used by default // Not used by default

View File

@ -172,7 +172,7 @@ void posixSocket::sendRaw(const char* buffer, const int count)
// posixSocketFactory // posixSocketFactory
// //
ref <vmime::messaging::socket> posixSocketFactory::create() ref <vmime::net::socket> posixSocketFactory::create()
{ {
return vmime::create <posixSocket>(); return vmime::create <posixSocket>();
} }

View File

@ -233,14 +233,14 @@ const unsigned int windowsHandler::getProcessId() const
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
vmime::messaging::socketFactory* windowsHandler::getSocketFactory vmime::net::socketFactory* windowsHandler::getSocketFactory
(const vmime::string& /* name */) const (const vmime::string& /* name */) const
{ {
return (m_socketFactory); return (m_socketFactory);
} }
vmime::messaging::timeoutHandlerFactory* windowsHandler::getTimeoutHandlerFactory vmime::net::timeoutHandlerFactory* windowsHandler::getTimeoutHandlerFactory
(const vmime::string& /* name */) const (const vmime::string& /* name */) const
{ {
// Not used by default // Not used by default

View File

@ -167,7 +167,7 @@ void windowsSocket::sendRaw(const char* buffer, const int count)
// posixSocketFactory // posixSocketFactory
// //
ref <vmime::messaging::socket> windowsSocketFactory::create() ref <vmime::net::socket> windowsSocketFactory::create()
{ {
return vmime::create <windowsSocket>(); return vmime::create <windowsSocket>();
} }

View File

@ -24,7 +24,7 @@
#include <iterator> // for std::back_inserter #include <iterator> // for std::back_inserter
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
#include "vmime/messaging/socket.hpp" #include "vmime/net/socket.hpp"
#endif #endif
@ -331,7 +331,7 @@ const stream::size_type inputStreamPointerAdapter::skip(const size_type count)
// outputStreamSocketAdapter // outputStreamSocketAdapter
outputStreamSocketAdapter::outputStreamSocketAdapter(messaging::socket& sok) outputStreamSocketAdapter::outputStreamSocketAdapter(net::socket& sok)
: m_socket(sok) : m_socket(sok)
{ {
} }
@ -346,7 +346,7 @@ void outputStreamSocketAdapter::write
// inputStreamSocketAdapter // inputStreamSocketAdapter
inputStreamSocketAdapter::inputStreamSocketAdapter(messaging::socket& sok) inputStreamSocketAdapter::inputStreamSocketAdapter(net::socket& sok)
: m_socket(sok) : m_socket(sok)
{ {
} }

View File

@ -338,26 +338,32 @@ public:
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
/** Base class for exceptions thrown by the messaging module. /** Base class for exceptions thrown by the networking module.
*/ */
class messaging_exception : public vmime::exception class net_exception : public vmime::exception
{ {
public: public:
messaging_exception(const string& what, const exception& other = NO_EXCEPTION); net_exception(const string& what, const exception& other = NO_EXCEPTION);
~messaging_exception() throw(); ~net_exception() throw();
exception* clone() const; exception* clone() const;
const char* name() const throw(); const char* name() const throw();
}; };
/** Alias for 'net_exception' (compatibility with version <= 0.7.1);
* this is deprecated.
*/
typedef net_exception messaging_exception;
/** Error while connecting to the server: this may be a DNS resolution error /** Error while connecting to the server: this may be a DNS resolution error
* or a connection error (for example, time-out while connecting). * or a connection error (for example, time-out while connecting).
*/ */
class connection_error : public messaging_exception class connection_error : public net_exception
{ {
public: public:
@ -372,7 +378,7 @@ public:
/** Server did not initiated the connection correctly. /** Server did not initiated the connection correctly.
*/ */
class connection_greeting_error : public messaging_exception class connection_greeting_error : public net_exception
{ {
public: public:
@ -394,7 +400,7 @@ private:
* or password, or wrong authentication method). * or password, or wrong authentication method).
*/ */
class authentication_error : public messaging_exception class authentication_error : public net_exception
{ {
public: public:
@ -415,7 +421,7 @@ private:
/** Option not supported. /** Option not supported.
*/ */
class unsupported_option : public messaging_exception class unsupported_option : public net_exception
{ {
public: public:
@ -430,7 +436,7 @@ public:
/** No service available for this protocol. /** No service available for this protocol.
*/ */
class no_service_available : public messaging_exception class no_service_available : public net_exception
{ {
public: public:
@ -446,7 +452,7 @@ public:
* operation (for example, you try to close a folder which is not open). * operation (for example, you try to close a folder which is not open).
*/ */
class illegal_state : public messaging_exception class illegal_state : public net_exception
{ {
public: public:
@ -461,7 +467,7 @@ public:
/** Folder not found (does not exist). /** Folder not found (does not exist).
*/ */
class folder_not_found : public messaging_exception class folder_not_found : public net_exception
{ {
public: public:
@ -476,7 +482,7 @@ public:
/** Message not found (does not exist). /** Message not found (does not exist).
*/ */
class message_not_found : public messaging_exception class message_not_found : public net_exception
{ {
public: public:
@ -491,7 +497,7 @@ public:
/** Operation not supported by the underlying protocol. /** Operation not supported by the underlying protocol.
*/ */
class operation_not_supported : public messaging_exception class operation_not_supported : public net_exception
{ {
public: public:
@ -506,7 +512,7 @@ public:
/** The operation timed out (time-out delay is elapsed). /** The operation timed out (time-out delay is elapsed).
*/ */
class operation_timed_out : public messaging_exception class operation_timed_out : public net_exception
{ {
public: public:
@ -521,7 +527,7 @@ public:
/** The operation has been cancelled. /** The operation has been cancelled.
*/ */
class operation_cancelled : public messaging_exception class operation_cancelled : public net_exception
{ {
public: public:
@ -537,7 +543,7 @@ public:
* the requested object. * the requested object.
*/ */
class unfetched_object : public messaging_exception class unfetched_object : public net_exception
{ {
public: public:
@ -552,7 +558,7 @@ public:
/** The service is not currently connected. /** The service is not currently connected.
*/ */
class not_connected : public messaging_exception class not_connected : public net_exception
{ {
public: public:
@ -567,7 +573,7 @@ public:
/** The service is already connected (must disconnect before). /** The service is already connected (must disconnect before).
*/ */
class already_connected : public messaging_exception class already_connected : public net_exception
{ {
public: public:
@ -582,7 +588,7 @@ public:
/** Illegal operation: cannot run this operation on the object. /** Illegal operation: cannot run this operation on the object.
*/ */
class illegal_operation : public messaging_exception class illegal_operation : public net_exception
{ {
public: public:
@ -597,7 +603,7 @@ public:
/** Command error: operation failed (this is specific to the underlying protocol). /** Command error: operation failed (this is specific to the underlying protocol).
*/ */
class command_error : public messaging_exception class command_error : public net_exception
{ {
public: public:
@ -631,7 +637,7 @@ private:
/** The server returned an invalid response. /** The server returned an invalid response.
*/ */
class invalid_response : public messaging_exception class invalid_response : public net_exception
{ {
public: public:
@ -665,7 +671,7 @@ private:
/** Partial fetch is not supported by the underlying protocol. /** Partial fetch is not supported by the underlying protocol.
*/ */
class partial_fetch_not_supported : public messaging_exception class partial_fetch_not_supported : public net_exception
{ {
public: public:
@ -680,7 +686,7 @@ public:
/** The URL is malformed. /** The URL is malformed.
*/ */
class malformed_url : public messaging_exception class malformed_url : public net_exception
{ {
public: public:
@ -695,7 +701,7 @@ public:
/** Folder name is invalid. /** Folder name is invalid.
*/ */
class invalid_folder_name : public messaging_exception class invalid_folder_name : public net_exception
{ {
public: public:

38
vmime/net/authHelper.hpp Normal file
View File

@ -0,0 +1,38 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_AUTHHELPER_HPP_INCLUDED
#define VMIME_NET_AUTHHELPER_HPP_INCLUDED
#include "vmime/types.hpp"
namespace vmime {
namespace net {
void hmac_md5(const string& text, const string& key, string& hexDigest);
} // net
} // vmime
#endif // VMIME_NET_AUTHHELPER_HPP_INCLUDED

View File

@ -0,0 +1,64 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED
#define VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED
#include "vmime/types.hpp"
namespace vmime {
namespace net {
/** This class encapsulates user credentials.
*/
class authenticationInfos : public object
{
public:
authenticationInfos(const string& username, const string& password);
authenticationInfos(const authenticationInfos& infos);
/** Return the user account name.
*
* @return account name
*/
const string& getUsername() const;
/** Return the user account password.
*
* @return account password
*/
const string& getPassword() const;
private:
string m_username;
string m_password;
};
} // net
} // vmime
#endif // VMIME_NET_AUTHENTICATIONINFOS_HPP_INCLUDED

View File

@ -0,0 +1,54 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_AUTHENTICATOR_HPP_INCLUDED
#define VMIME_NET_AUTHENTICATOR_HPP_INCLUDED
#include "vmime/types.hpp"
#include "vmime/net/authenticationInfos.hpp"
namespace vmime {
namespace net {
/** This class is used to obtain user credentials.
*/
class authenticator : public object
{
public:
virtual ~authenticator();
/** Called when the service needs to retrieve user credentials.
* It should return the user account name and password.
*
* @return user credentials (user name and password)
*/
virtual const authenticationInfos requestAuthInfos() const = 0;
};
} // net
} // vmime
#endif // VMIME_NET_AUTHENTICATOR_HPP_INCLUDED

View File

@ -0,0 +1,60 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED
#define VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED
#include "vmime/net/authenticator.hpp"
#include "vmime/propertySet.hpp"
namespace vmime {
namespace net {
class session;
/** Default implementation for authenticator. It simply returns
* the credentials set in the session properties (named 'username'
* and 'password'). This is the default implementation used if
* you do not write your own authenticator object.
*/
class defaultAuthenticator : public authenticator
{
public:
defaultAuthenticator(weak_ref <session> session, const string& prefix);
private:
weak_ref <session> m_session;
const string m_prefix;
const authenticationInfos requestAuthInfos() const;
};
} // net
} // vmime
#endif // VMIME_NET_DEFAULTAUTHENTICATOR_HPP_INCLUDED

229
vmime/net/events.hpp Normal file
View File

@ -0,0 +1,229 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_EVENTS_HPP_INCLUDED
#define VMIME_NET_EVENTS_HPP_INCLUDED
#include <vector>
#include "vmime/utility/path.hpp"
namespace vmime {
namespace net {
class folder;
namespace events {
/** Event about the message count in a folder.
*/
class messageCountEvent
{
public:
enum Types
{
TYPE_ADDED, /**< New messages have been added. */
TYPE_REMOVED /**< Messages have been expunged (renumbering). */
};
messageCountEvent(ref <folder> folder, const Types type, const std::vector <int>& nums);
/** Return the folder in which messages have been added/removed.
*
* @return folder in which message count changed
*/
ref <const folder> getFolder() const;
/** Return the event type.
*
* @return event type (see messageCountEvent::Types)
*/
const Types getType() const;
/** Return the numbers of the messages that have been added/removed.
*
* @return a list of message numbers
*/
const std::vector <int>& getNumbers() const;
/** Dispatch the event to the specified listener.
*
* @param listener listener to notify
*/
void dispatch(class messageCountListener* listener) const;
private:
ref <folder> m_folder;
const Types m_type;
std::vector <int> m_nums;
};
/** Listener for events about the message count in a folder.
*/
class messageCountListener
{
protected:
virtual ~messageCountListener() { }
public:
virtual void messagesAdded(const messageCountEvent& event) = 0;
virtual void messagesRemoved(const messageCountEvent& event) = 0;
};
/** Event occuring on a message.
*/
class messageChangedEvent
{
public:
enum Types
{
TYPE_FLAGS // flags changed
};
messageChangedEvent(ref <folder> folder, const Types type, const std::vector <int>& nums);
/** Return the folder in which messages have changed.
*
* @return folder in which message count changed
*/
ref <const folder> getFolder() const;
/** Return the event type.
*
* @return event type (see messageChangedEvent::Types)
*/
const Types getType() const;
/** Return the numbers of the messages that have changed.
*
* @return a list of message numbers
*/
const std::vector <int>& getNumbers() const;
/** Dispatch the event to the specified listener.
*
* @param listener listener to notify
*/
void dispatch(class messageChangedListener* listener) const;
private:
ref <folder> m_folder;
const Types m_type;
std::vector <int> m_nums;
};
/** Listener for events occuring on a message.
*/
class messageChangedListener
{
protected:
virtual ~messageChangedListener() { }
public:
virtual void messageChanged(const messageChangedEvent& event) = 0;
};
/** Event occuring on a folder.
*/
class folderEvent
{
public:
enum Types
{
TYPE_CREATED, /**< A folder was created. */
TYPE_DELETED, /**< A folder was deleted. */
TYPE_RENAMED /**< A folder was renamed. */
};
folderEvent(ref <folder> folder, const Types type, const utility::path& oldPath, const utility::path& newPath);
/** Return the folder on which the event occured.
*
* @return folder on which the event occured
*/
ref <const folder> getFolder() const;
/** Return the event type.
*
* @return event type (see folderEvent::Types)
*/
const Types getType() const;
/** Dispatch the event to the specified listener.
*
* @param listener listener to notify
*/
void dispatch(class folderListener* listener) const;
private:
ref <folder> m_folder;
const Types m_type;
const utility::path m_oldPath;
const utility::path m_newPath;
};
/** Listener for events occuring on a folder.
*/
class folderListener
{
protected:
virtual ~folderListener() { }
public:
virtual void folderCreated(const folderEvent& event) = 0;
virtual void folderRenamed(const folderEvent& event) = 0;
virtual void folderDeleted(const folderEvent& event) = 0;
};
} // events
} // net
} // vmime
#endif // VMIME_NET_EVENTS_HPP_INCLUDED

379
vmime/net/folder.hpp Normal file
View File

@ -0,0 +1,379 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_FOLDER_HPP_INCLUDED
#define VMIME_NET_FOLDER_HPP_INCLUDED
#include <vector>
#include "vmime/types.hpp"
#include "vmime/dateTime.hpp"
#include "vmime/message.hpp"
#include "vmime/net/message.hpp"
#include "vmime/net/events.hpp"
#include "vmime/utility/path.hpp"
#include "vmime/utility/stream.hpp"
#include "vmime/utility/progressionListener.hpp"
namespace vmime {
namespace net {
class store;
/** Abstract representation of a folder in a message store.
*/
class folder : public object
{
protected:
folder(const folder&) : object() { }
folder() { }
public:
virtual ~folder() { }
/** Type used for fully qualified path name of a folder.
*/
typedef vmime::utility::path path;
/** Open mode.
*/
enum Modes
{
MODE_READ_ONLY, /**< Read-only mode (no modification to folder or messages is possible). */
MODE_READ_WRITE /**< Full access mode (read and write). */
};
/** Folder types.
*/
enum Types
{
TYPE_CONTAINS_FOLDERS = (1 << 0), /**< Folder can contain folders. */
TYPE_CONTAINS_MESSAGES = (1 << 1), /**< Folder can contain messages. */
TYPE_UNDEFINED = 9999 /**< Used internally (this should not be returned
by the type() function). */
};
/** Folder flags.
*/
enum Flags
{
FLAG_CHILDREN = (1 << 0), /**< Folder contains subfolders. */
FLAG_NO_OPEN = (1 << 1), /**< Folder cannot be open. */
FLAG_UNDEFINED = 9999 /**< Used internally (this should not be returned
by the type() function). */
};
/** Return the type of this folder.
*
* @return folder type (see folder::Types)
*/
virtual const int getType() = 0;
/** Return the flags of this folder.
*
* @return folder flags (see folder::Flags)
*/
virtual const int getFlags() = 0;
/** Return the mode in which the folder has been open.
*
* @return folder opening mode (see folder::Modes)
*/
virtual const int getMode() const = 0;
/** Return the name of this folder.
*
* @return folder name
*/
virtual const folder::path::component getName() const = 0;
/** Return the fully qualified path name of this folder.
*
* @return absolute path of the folder
*/
virtual const folder::path getFullPath() const = 0;
/** Open this folder.
*
* @param mode open mode (see folder::Modes)
* @param failIfModeIsNotAvailable if set to false and if the requested mode
* is not available, a more restricted mode will be selected automatically.
* If set to true and if the requested mode is not available, the opening
* will fail.
*/
virtual void open(const int mode, bool failIfModeIsNotAvailable = false) = 0;
/** Close this folder.
*
* @param expunge if set to true, deleted messages are expunged
*/
virtual void close(const bool expunge) = 0;
/** Create this folder.
*
* @param type folder type (see folder::Types)
*/
virtual void create(const int type) = 0;
/** Test whether this folder exists.
*
* @return true if the folder exists, false otherwise
*/
virtual const bool exists() = 0;
/** Test whether this folder is open.
*
* @return true if the folder is open, false otherwise
*/
virtual const bool isOpen() const = 0;
/** Get a new reference to a message in this folder.
*
* @param num message sequence number
* @return a new object referencing the specified message
*/
virtual ref <message> getMessage(const int num) = 0;
/** Get new references to messages in this folder.
*
* @param from sequence number of the first message to get
* @param to sequence number of the last message to get
* @return new objects referencing the specified messages
*/
virtual std::vector <ref <message> > getMessages(const int from = 1, const int to = -1) = 0;
/** Get new references to messages in this folder.
*
* @param nums sequence numbers of the messages to delete
* @return new objects referencing the specified messages
*/
virtual std::vector <ref <message> > getMessages(const std::vector <int>& nums) = 0;
/** Return the number of messages in this folder.
*
* @return number of messages in the folder
*/
virtual const int getMessageCount() = 0;
/** Get a new reference to a sub-folder in this folder.
*
* @param name sub-folder name
* @return a new object referencing the specified folder
*/
virtual ref <folder> getFolder(const folder::path::component& name) = 0;
/** Get the list of all sub-folders in this folder.
*
* @param recursive if set to true, all the descendant are returned.
* If set to false, only the direct children are returned.
* @return list of sub-folders
*/
virtual std::vector <ref <folder> > getFolders(const bool recursive = false) = 0;
/** Rename (move) this folder to another location.
*
* @param newPath new path of the folder
*/
virtual void rename(const folder::path& newPath) = 0;
/** Remove a message in this folder.
*
* @param num sequence number of the message to delete
*/
virtual void deleteMessage(const int num) = 0;
/** Remove one or more messages from this folder.
*
* @param from sequence number of the first message to delete
* @param to sequence number of the last message to delete
*/
virtual void deleteMessages(const int from = 1, const int to = -1) = 0;
/** Remove one or more messages from this folder.
*
* @param nums sequence numbers of the messages to delete
*/
virtual void deleteMessages(const std::vector <int>& nums) = 0;
/** Change the flags for one or more messages in this folder.
*
* @param from sequence number of the first message to modify
* @param to sequence number of the last message to modify
* @param flags set of flags (see message::Flags)
* @param mode indicate how to treat old and new flags (see message::FlagsModes)
*/
virtual void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
/** Change the flags for one or more messages in this folder.
*
* @param nums sequence numbers of the messages to modify
* @param flags set of flags (see message::Flags)
* @param mode indicate how to treat old and new flags (see message::FlagsModes)
*/
virtual void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
/** Add a message to this folder.
*
* @param msg message to add (data: header + body)
* @param flags flags for the new message
* @param date date/time for the new message (if NULL, the current time is used)
* @param progress progression listener, or NULL if not used
*/
virtual void addMessage(ref <vmime::message> msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL) = 0;
/** Add a message to this folder.
*
* @param is message to add (data: header + body)
* @param size size of the message to add (in bytes)
* @param flags flags for the new message
* @param date date/time for the new message (if NULL, the current time is used)
* @param progress progression listener, or NULL if not used
*/
virtual void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL) = 0;
/** Copy a message from this folder to another folder.
*
* @param dest destination folder path
* @param num sequence number of the message to copy
*/
virtual void copyMessage(const folder::path& dest, const int num) = 0;
/** Copy messages from this folder to another folder.
*
* @param dest destination folder path
* @param from sequence number of the first message to copy
* @param to sequence number of the last message to copy
*/
virtual void copyMessages(const folder::path& dest, const int from = 1, const int to = -1) = 0;
/** Copy messages from this folder to another folder.
*
* @param dest destination folder path
* @param nums sequence numbers of the messages to copy
*/
virtual void copyMessages(const folder::path& dest, const std::vector <int>& nums) = 0;
/** Request folder status without opening it.
*
* @param count will receive the number of messages in the folder
* @param unseen will receive the number of unseen messages in the folder
*/
virtual void status(int& count, int& unseen) = 0;
/** Expunge deleted messages.
*/
virtual void expunge() = 0;
/** Return a new folder object referencing the parent folder of this folder.
*
* @return parent folder object
*/
virtual ref <folder> getParent() = 0;
/** Return a reference to the store to which this folder belongs.
*
* @return the store object to which this folder is attached
*/
virtual weak_ref <const store> getStore() const = 0;
/** Return a reference to the store to which this folder belongs.
*
* @return the store object to which this folder is attached
*/
virtual weak_ref <store> getStore() = 0;
/** Fetchable objects.
*/
enum FetchOptions
{
FETCH_ENVELOPE = (1 << 0), /**< Fetch sender, recipients, date, subject. */
FETCH_STRUCTURE = (1 << 1), /**< Fetch structure (body parts). */
FETCH_CONTENT_INFO = (1 << 2), /**< Fetch top-level content type. */
FETCH_FLAGS = (1 << 3), /**< Fetch message flags. */
FETCH_SIZE = (1 << 4), /**< Fetch message size (exact or estimated). */
FETCH_FULL_HEADER = (1 << 5), /**< Fetch full RFC-[2]822 header. */
FETCH_UID = (1 << 6), /**< Fetch unique identifier (protocol specific). */
FETCH_IMPORTANCE = (1 << 7), /**< Fetch header fields suitable for use with misc::importanceHelper. */
FETCH_CUSTOM = (1 << 16) /**< Reserved for future use. */
};
/** Fetch objects for the specified messages.
*
* @param msg list of message sequence numbers
* @param options objects to fetch (combination of folder::FetchOptions flags)
* @param progress progression listener, or NULL if not used
*/
virtual void fetchMessages(std::vector <ref <message> >& msg, const int options, utility::progressionListener* progress = NULL) = 0;
/** Fetch objects for the specified message.
*
* @param msg the message
* @param options objects to fetch (combination of folder::FetchOptions flags)
*/
virtual void fetchMessage(ref <message> msg, const int options) = 0;
/** Return the list of fetchable objects supported by
* the underlying protocol (see folder::FetchOptions).
*
* @return list of supported fetchable objects
*/
virtual const int getFetchCapabilities() const = 0;
// Event listeners
void addMessageChangedListener(events::messageChangedListener* l);
void removeMessageChangedListener(events::messageChangedListener* l);
void addMessageCountListener(events::messageCountListener* l);
void removeMessageCountListener(events::messageCountListener* l);
void addFolderListener(events::folderListener* l);
void removeFolderListener(events::folderListener* l);
protected:
void notifyMessageChanged(const events::messageChangedEvent& event);
void notifyMessageCount(const events::messageCountEvent& event);
void notifyFolder(const events::folderEvent& event);
private:
std::list <events::messageChangedListener*> m_messageChangedListeners;
std::list <events::messageCountListener*> m_messageCountListeners;
std::list <events::folderListener*> m_folderListeners;
};
} // net
} // vmime
#endif // VMIME_NET_FOLDER_HPP_INCLUDED

View File

@ -0,0 +1,116 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
#define VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
#include "vmime/config.hpp"
#include "vmime/net/authenticator.hpp"
#include "vmime/net/socket.hpp"
#include "vmime/net/timeoutHandler.hpp"
#include "vmime/net/session.hpp"
#include "vmime/net/imap/IMAPParser.hpp"
namespace vmime {
namespace net {
namespace imap {
class IMAPTag;
class IMAPStore;
class IMAPConnection : public object
{
public:
IMAPConnection(weak_ref <IMAPStore> store, ref <authenticator> auth);
~IMAPConnection();
void connect();
const bool isConnected() const;
void disconnect();
enum ProtocolStates
{
STATE_NONE,
STATE_NON_AUTHENTICATED,
STATE_AUTHENTICATED,
STATE_SELECTED,
STATE_LOGOUT
};
const ProtocolStates state() const;
void setState(const ProtocolStates state);
const char hierarchySeparator() const;
void send(bool tag, const string& what, bool end);
void sendRaw(const char* buffer, const int count);
IMAPParser::response* readResponse(IMAPParser::literalHandler* lh = NULL);
ref <const IMAPTag> getTag() const;
ref <const IMAPParser> getParser() const;
weak_ref <const IMAPStore> getStore() const;
weak_ref <IMAPStore> getStore();
ref <session> getSession();
private:
weak_ref <IMAPStore> m_store;
ref <authenticator> m_auth;
ref <socket> m_socket;
ref <IMAPParser> m_parser;
ref <IMAPTag> m_tag;
char m_hierarchySeparator;
ProtocolStates m_state;
ref <timeoutHandler> m_timeoutHandler;
void internalDisconnect();
void initHierarchySeparator();
};
} // imap
} // net
} // vmime
#endif // VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED

View File

@ -0,0 +1,158 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
#define VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
#include <vector>
#include <map>
#include "vmime/types.hpp"
#include "vmime/net/folder.hpp"
namespace vmime {
namespace net {
namespace imap {
class IMAPStore;
class IMAPMessage;
class IMAPConnection;
/** IMAP folder implementation.
*/
class IMAPFolder : public folder
{
private:
friend class IMAPStore;
friend class IMAPMessage;
friend class vmime::creator; // vmime::create <IMAPFolder>
IMAPFolder(const folder::path& path, IMAPStore* store, const int type = TYPE_UNDEFINED, const int flags = FLAG_UNDEFINED);
IMAPFolder(const IMAPFolder&) : folder() { }
~IMAPFolder();
public:
const int getMode() const;
const int getType();
const int getFlags();
const folder::path::component getName() const;
const folder::path getFullPath() const;
void open(const int mode, bool failIfModeIsNotAvailable = false);
void close(const bool expunge);
void create(const int type);
const bool exists();
const bool isOpen() const;
ref <message> getMessage(const int num);
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
const int getMessageCount();
ref <folder> getFolder(const folder::path::component& name);
std::vector <ref <folder> > getFolders(const bool recursive = false);
void rename(const folder::path& newPath);
void deleteMessage(const int num);
void deleteMessages(const int from = 1, const int to = -1);
void deleteMessages(const std::vector <int>& nums);
void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
void addMessage(ref <vmime::message> msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL);
void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL);
void copyMessage(const folder::path& dest, const int num);
void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
void status(int& count, int& unseen);
void expunge();
ref <folder> getParent();
weak_ref <const store> getStore() const;
weak_ref <store> getStore();
void fetchMessages(std::vector <ref <message> >& msg, const int options, utility::progressionListener* progress = NULL);
void fetchMessage(ref <message> msg, const int options);
const int getFetchCapabilities() const;
private:
void registerMessage(IMAPMessage* msg);
void unregisterMessage(IMAPMessage* msg);
void onStoreDisconnected();
void onClose();
const int testExistAndGetType();
void setMessageFlags(const string& set, const int flags, const int mode);
void copyMessages(const string& set, const folder::path& dest);
IMAPStore* m_store;
ref <IMAPConnection> m_connection;
folder::path m_path;
folder::path::component m_name;
int m_mode;
bool m_open;
int m_type;
int m_flags;
int m_messageCount;
int m_uidValidity;
std::vector <IMAPMessage*> m_messages;
};
} // imap
} // net
} // vmime
#endif // VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED

View File

@ -0,0 +1,111 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
#define VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
#include "vmime/net/message.hpp"
#include "vmime/net/folder.hpp"
#include "vmime/mailboxList.hpp"
namespace vmime {
namespace net {
namespace imap {
class IMAPFolder;
/** IMAP message implementation.
*/
class IMAPMessage : public message
{
private:
friend class IMAPFolder;
friend class vmime::creator; // vmime::create <IMAPMessage>
IMAPMessage(IMAPFolder* folder, const int num);
IMAPMessage(const IMAPMessage&) : message() { }
~IMAPMessage();
public:
const int getNumber() const;
const uid getUniqueId() const;
const int getSize() const;
const bool isExpunged() const;
const structure& getStructure() const;
structure& getStructure();
ref <const header> getHeader() const;
const int getFlags() const;
void setFlags(const int flags, const int mode = FLAG_MODE_SET);
void extract(utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const;
void extractPart(const part& p, utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const;
void fetchPartHeader(part& p);
private:
void fetch(IMAPFolder* folder, const int options);
void processFetchResponse(const int options, const IMAPParser::msg_att* msgAtt);
void extract(const part* p, utility::outputStream& os, utility::progressionListener* progress, const int start, const int length, const bool headerOnly, const bool peek) const;
void convertAddressList(const IMAPParser::address_list& src, mailboxList& dest);
ref <header> getOrCreateHeader();
void onFolderClosed();
IMAPFolder* m_folder;
int m_num;
int m_size;
int m_flags;
bool m_expunged;
uid m_uid;
ref <header> m_header;
ref <structure> m_structure;
};
} // imap
} // net
} // vmime
#endif // VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,137 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
#define VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
#include "vmime/config.hpp"
#include "vmime/net/store.hpp"
#include "vmime/net/socket.hpp"
#include "vmime/net/folder.hpp"
#include <ostream>
namespace vmime {
namespace net {
namespace imap {
class IMAPParser;
class IMAPTag;
class IMAPConnection;
class IMAPFolder;
/** IMAP store service.
*/
class IMAPStore : public store
{
friend class IMAPFolder;
friend class IMAPMessage;
friend class IMAPConnection;
public:
IMAPStore(ref <session> sess, ref <authenticator> auth);
~IMAPStore();
const string getProtocolName() const;
ref <folder> getDefaultFolder();
ref <folder> getRootFolder();
ref <folder> getFolder(const folder::path& path);
const bool isValidFolderName(const folder::path::component& name) const;
static const serviceInfos& getInfosInstance();
const serviceInfos& getInfos() const;
void connect();
const bool isConnected() const;
void disconnect();
void noop();
const int getCapabilities() const;
private:
// Connection
ref <IMAPConnection> m_connection;
// Used to request the authentication informations only the
// first time, and reuse these informations the next time.
ref <class authenticator> m_oneTimeAuth;
ref <class authenticator> oneTimeAuthenticator();
ref <IMAPConnection> connection();
void registerFolder(IMAPFolder* folder);
void unregisterFolder(IMAPFolder* folder);
std::list <IMAPFolder*> m_folders;
// Service infos
class _infos : public serviceInfos
{
public:
struct props
{
// IMAP-specific options
// (none)
// Common properties
serviceInfos::property PROPERTY_AUTH_USERNAME;
serviceInfos::property PROPERTY_AUTH_PASSWORD;
serviceInfos::property PROPERTY_SERVER_ADDRESS;
serviceInfos::property PROPERTY_SERVER_PORT;
serviceInfos::property PROPERTY_SERVER_SOCKETFACTORY;
serviceInfos::property PROPERTY_TIMEOUT_FACTORY;
};
const props& getProperties() const;
const string getPropertyPrefix() const;
const std::vector <serviceInfos::property> getAvailableProperties() const;
};
static _infos sm_infos;
};
} // imap
} // net
} // vmime
#endif // VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED

View File

@ -0,0 +1,66 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
#define VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
#include "vmime/types.hpp"
namespace vmime {
namespace net {
namespace imap {
class IMAPTag : public object
{
private:
IMAPTag(const int number);
IMAPTag(const IMAPTag& tag);
public:
IMAPTag();
IMAPTag& operator++(); // ++IMAPTag
const IMAPTag operator++(int); // IMAPTag++
const int number() const;
operator string() const;
private:
void generate();
static const int sm_maxNumber;
int m_number;
string m_tag;
};
} // imap
} // net
} // vmime
#endif // VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED

View File

@ -0,0 +1,68 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
#define VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
#include "vmime/types.hpp"
#include "vmime/dateTime.hpp"
#include "vmime/net/folder.hpp"
#include "vmime/net/imap/IMAPParser.hpp"
#include <vector>
namespace vmime {
namespace net {
namespace imap {
class IMAPUtils
{
public:
static const string pathToString(const char hierarchySeparator, const folder::path& path);
static const folder::path stringToPath(const char hierarchySeparator, const string& str);
static const string toModifiedUTF7(const char hierarchySeparator, const folder::path::component& text);
static const folder::path::component fromModifiedUTF7(const string& text);
static const string quoteString(const string& text);
static const int folderTypeFromFlags(const IMAPParser::mailbox_flag_list* list);
static const int folderFlagsFromFlags(const IMAPParser::mailbox_flag_list* list);
static const int messageFlagsFromFlags(const IMAPParser::flag_list* list);
static const string messageFlagList(const int flags);
static const string listToSet(const std::vector <int>& list, const int max = -1, const bool alreadySorted = false);
static const string dateTime(const vmime::datetime& date);
};
} // imap
} // net
} // vmime
#endif // VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED

View File

@ -0,0 +1,178 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
#define VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
#include <vector>
#include <map>
#include "vmime/types.hpp"
#include "vmime/net/folder.hpp"
#include "vmime/utility/file.hpp"
namespace vmime {
namespace net {
namespace maildir {
class maildirStore;
class maildirMessage;
/** maildir folder implementation.
*/
class maildirFolder : public folder
{
private:
friend class maildirStore;
friend class maildirMessage;
friend class vmime::creator; // vmime::create <maildirFolder>
maildirFolder(const folder::path& path, weak_ref <maildirStore> store);
maildirFolder(const maildirFolder&) : folder() { }
~maildirFolder();
public:
const int getMode() const;
const int getType();
const int getFlags();
const folder::path::component getName() const;
const folder::path getFullPath() const;
void open(const int mode, bool failIfModeIsNotAvailable = false);
void close(const bool expunge);
void create(const int type);
const bool exists();
const bool isOpen() const;
ref <message> getMessage(const int num);
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
const int getMessageCount();
ref <folder> getFolder(const folder::path::component& name);
std::vector <ref <folder> > getFolders(const bool recursive = false);
void rename(const folder::path& newPath);
void deleteMessage(const int num);
void deleteMessages(const int from = 1, const int to = -1);
void deleteMessages(const std::vector <int>& nums);
void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
void addMessage(ref <vmime::message> msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL);
void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL);
void copyMessage(const folder::path& dest, const int num);
void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
void status(int& count, int& unseen);
void expunge();
ref <folder> getParent();
weak_ref <const store> getStore() const;
weak_ref <store> getStore();
void fetchMessages(std::vector <ref <message> >& msg, const int options, utility::progressionListener* progress = NULL);
void fetchMessage(ref <message> msg, const int options);
const int getFetchCapabilities() const;
private:
void scanFolder();
void listFolders(std::vector <ref <folder> >& list, const bool recursive);
void registerMessage(maildirMessage* msg);
void unregisterMessage(maildirMessage* msg);
const utility::file::path getMessageFSPath(const int number) const;
void onStoreDisconnected();
void onClose();
void deleteMessagesImpl(const std::vector <int>& nums);
void setMessageFlagsImpl(const std::vector <int>& nums, const int flags, const int mode);
void copyMessagesImpl(const folder::path& dest, const std::vector <int>& nums);
void copyMessageImpl(const utility::file::path& tmpDirPath, const utility::file::path& curDirPath, const utility::file::path::component& filename, utility::inputStream& is, const utility::stream::size_type size, utility::progressionListener* progress);
void notifyMessagesCopied(const folder::path& dest);
weak_ref <maildirStore> m_store;
folder::path m_path;
folder::path::component m_name;
int m_mode;
bool m_open;
int m_unreadMessageCount;
int m_messageCount;
// Store information about scanned messages
struct messageInfos
{
enum Type
{
TYPE_CUR,
TYPE_DELETED
};
utility::file::path::component path; // filename
Type type; // current location
};
std::vector <messageInfos> m_messageInfos;
// Instanciated message objects
std::vector <maildirMessage*> m_messages;
};
} // maildir
} // net
} // vmime
#endif // VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED

View File

@ -0,0 +1,103 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
#define VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
#include "vmime/net/message.hpp"
#include "vmime/net/folder.hpp"
namespace vmime {
namespace net {
namespace maildir {
class maildirFolder;
/** maildir message implementation.
*/
class maildirMessage : public message
{
friend class maildirFolder;
friend class vmime::creator; // vmime::create <maildirMessage>
private:
maildirMessage(weak_ref <maildirFolder> folder, const int num);
maildirMessage(const maildirMessage&) : message() { }
~maildirMessage();
public:
const int getNumber() const;
const uid getUniqueId() const;
const int getSize() const;
const bool isExpunged() const;
const structure& getStructure() const;
structure& getStructure();
ref <const header> getHeader() const;
const int getFlags() const;
void setFlags(const int flags, const int mode = FLAG_MODE_SET);
void extract(utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const;
void extractPart(const part& p, utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const;
void fetchPartHeader(part& p);
private:
void fetch(weak_ref <maildirFolder> folder, const int options);
void onFolderClosed();
ref <header> getOrCreateHeader();
void extractImpl(utility::outputStream& os, utility::progressionListener* progress, const int start, const int length, const int partialStart, const int partialLength, const bool peek) const;
weak_ref <maildirFolder> m_folder;
int m_num;
int m_size;
int m_flags;
bool m_expunged;
uid m_uid;
ref <header> m_header;
ref <structure> m_structure;
};
} // maildir
} // net
} // vmime
#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED

View File

@ -0,0 +1,114 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
#define VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
#include "vmime/config.hpp"
#include "vmime/net/store.hpp"
#include "vmime/net/socket.hpp"
#include "vmime/net/folder.hpp"
#include "vmime/utility/file.hpp"
#include <ostream>
namespace vmime {
namespace net {
namespace maildir {
class maildirFolder;
/** maildir store service.
*/
class maildirStore : public store
{
friend class maildirFolder;
public:
maildirStore(ref <session> sess, ref <authenticator> auth);
~maildirStore();
const string getProtocolName() const;
ref <folder> getDefaultFolder();
ref <folder> getRootFolder();
ref <folder> getFolder(const folder::path& path);
const bool isValidFolderName(const folder::path::component& name) const;
static const serviceInfos& getInfosInstance();
const serviceInfos& getInfos() const;
void connect();
const bool isConnected() const;
void disconnect();
void noop();
const utility::path& getFileSystemPath() const;
const int getCapabilities() const;
private:
void registerFolder(maildirFolder* folder);
void unregisterFolder(maildirFolder* folder);
std::list <maildirFolder*> m_folders;
bool m_connected;
utility::path m_fsPath;
// Service infos
class _infos : public serviceInfos
{
public:
struct props
{
serviceInfos::property PROPERTY_SERVER_ROOTPATH;
};
const props& getProperties() const;
const string getPropertyPrefix() const;
const std::vector <serviceInfos::property> getAvailableProperties() const;
};
static _infos sm_infos;
};
} // maildir
} // net
} // vmime
#endif // VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED

View File

@ -0,0 +1,160 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
#define VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
#include "vmime/utility/file.hpp"
#include "vmime/utility/path.hpp"
namespace vmime {
namespace net {
namespace maildir {
class maildirStore;
/** Miscellaneous helpers functions for maildir messaging system.
*/
class maildirUtils
{
public:
/** Comparator for message filenames, based only on the
* unique identifier part of the filename.
*/
class messageIdComparator
{
public:
messageIdComparator(const utility::file::path::component& comp);
const bool operator()(const utility::file::path::component& other) const;
private:
const utility::file::path::component m_comp;
};
/** Mode for return value of getFolderFSPath(). */
enum FolderFSPathMode
{
FOLDER_PATH_ROOT, /**< Root folder. Eg: ~/Mail/MyFolder */
FOLDER_PATH_NEW, /**< Folder containing unread messages. Eg: ~/Mail/MyFolder/new */
FOLDER_PATH_CUR, /**< Folder containing messages that have been seen. Eg: ~/Mail/MyFolder/cur */
FOLDER_PATH_TMP, /**< Temporary folder used for reliable delivery. Eg: ~/Mail/MyFolder/tmp */
FOLDER_PATH_CONTAINER /**< Container for sub-folders. Eg: ~/Mail/.MyFolder.directory */
};
/** Return the path on the filesystem for the folder in specified store.
*
* @param store parent store
* @param folderPath path of the folder
* @param mode type of path to return (see FolderFSPathMode)
* @return filesystem path for the specified folder
*/
static const utility::file::path getFolderFSPath(weak_ref <maildirStore> store,
const utility::path& folderPath, const FolderFSPathMode mode);
/** Test whether the specified file-system directory corresponds to
* a maildir sub-folder. The name of the directory should not start
* with '.' to be listed as a sub-folder.
*
* @param file reference to a file-system directory
* @return true if the specified directory is a maildir sub-folder,
* false otherwise
*/
static const bool isSubfolderDirectory(const utility::file& file);
/** Test whether the specified file-system object is a message.
*
* @param file reference to a file-system object
* @return true if the specified object is a message file,
* false otherwise
*/
static const bool isMessageFile(const utility::file& file);
/** Extract the unique identifier part of the message filename.
* Eg: for the filename "1071577232.28549.m03s:2,RS", it will
* return "1071577232.28549.m03s".
*
* @param filename filename part
* @return part of the filename that corresponds to the unique
* identifier of the message
*/
static const utility::file::path::component extractId(const utility::file::path::component& filename);
/** Extract message flags from the specified message filename.
* Eg: for the filename "1071577232.28549.m03s:2,RS", it will
* return (message::FLAG_SEEN | message::FLAG_REPLIED).
*
* @param comp filename part
* @return message flags extracted from the specified filename
*/
static const int extractFlags(const utility::file::path::component& comp);
/** Return a string representing the specified message flags.
* Eg: for (message::FLAG_SEEN | message::FLAG_REPLIED), it will
* return "RS".
*
* @param flags set of flags
* @return message flags in a string representation
*/
static const utility::file::path::component buildFlags(const int flags);
/** Build a filename with the specified id and flags.
*
* @param id id part of the filename
* @param flags flags part of the filename
* @return message filename
*/
static const utility::file::path::component buildFilename(const utility::file::path::component& id, const utility::file::path::component& flags);
/** Build a filename with the specified id and flags.
*
* @param id id part of the filename
* @param flags set of flags
* @return message filename
*/
static const utility::file::path::component buildFilename(const utility::file::path::component& id, const int flags);
/** Generate a new unique message identifier.
*
* @return unique message id
*/
static const utility::file::path::component generateId();
private:
static const vmime::word TMP_DIR;
static const vmime::word CUR_DIR;
static const vmime::word NEW_DIR;
};
} // maildir
} // net
} // vmime
#endif // VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED

292
vmime/net/message.hpp Normal file
View File

@ -0,0 +1,292 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_MESSAGE_HPP_INCLUDED
#define VMIME_NET_MESSAGE_HPP_INCLUDED
#include "vmime/header.hpp"
#include "vmime/utility/progressionListener.hpp"
#include "vmime/utility/stream.hpp"
namespace vmime {
namespace net {
class structure;
/** A MIME part in a message.
*/
class part : public object
{
protected:
part() { }
part(const part&) : object() { }
virtual ~part() { }
public:
/** Return the structure of this part.
*
* @return structure of the part
*/
virtual const structure& getStructure() const = 0;
/** Return the structure of this part.
*
* @return structure of the part
*/
virtual structure& getStructure() = 0;
/** Return the header section for this part (you must fetch header
* before using this function: see message::fetchPartHeader).
*
* @return header section
*/
virtual const header& getHeader() const = 0;
/** Return the media-type of the content in this part.
*
* @return content media type
*/
virtual const mediaType& getType() const = 0;
/** Return the size of this part.
*
* @return size of the part (in bytes)
*/
virtual const int getSize() const = 0;
/** Return the part sequence number (index)
*
* @return part number
*/
virtual const int getNumber() const = 0; // begin at 1
/** Return the sub-part at the specified position.
* This provide easy access to parts:
* Eg: "message->extractPart(message->getStructure()[3][1][2])".
*
* @param x index of the sub-part
* @return sub-part at position 'x'
*/
const part& operator[](const int x) const;
/** Return the sub-part at the specified position.
* This provide easy access to parts:
* Eg: "message->extractPart(message->getStructure()[3][1][2])".
*
* @param x index of the sub-part
* @return sub-part at position 'x'
*/
part& operator[](const int x);
/** Return the number of sub-parts in this part.
*
* @return number of sub-parts
*/
const int getCount() const;
};
/** Structure of a MIME part/message.
*/
class structure : public object
{
protected:
structure() { }
structure(const structure&) : object() { }
public:
virtual ~structure() { }
/** Return the part at the specified position (first
* part is at position 1).
*
* @param x position
* @return part at position 'x'
*/
virtual const part& operator[](const int x) const = 0;
/** Return the part at the specified position (first
* part is at position 1).
*
* @param x position
* @return part at position 'x'
*/
virtual part& operator[](const int x) = 0;
/** Return the number of parts in this part.
*
* @return number of parts
*/
virtual const int getCount() const = 0;
};
/** Abstract representation of a message in a store/transport service.
*/
class message : public object
{
protected:
message() { }
message(const message&) : object() { }
public:
virtual ~message() { }
/** The type for an unique message identifier.
*/
typedef string uid;
/** Return the MIME structure of the message (must fetch before).
*
* @return MIME structure of the message
*/
virtual const structure& getStructure() const = 0;
/** Return the MIME structure of the message (must fetch before).
*
* @return MIME structure of the message
*/
virtual structure& getStructure() = 0;
/** Return a reference to the header fields of the message (must fetch before).
*
* @return header section of the message
*/
virtual ref <const header> getHeader() const = 0;
/** Return the sequence number of this message. This number is
* used to reference the message in the folder.
*
* @return sequence number of the message
*/
virtual const int getNumber() const = 0;
/** Return the unique identified of this message (must fetch before).
*
* @return UID of the message
*/
virtual const uid getUniqueId() const = 0;
/** Return the size of the message (must fetch before).
*
* @return size of the message (in bytes)
*/
virtual const int getSize() const = 0;
/** Check whether this message has been expunged
* (ie: definitively deleted).
*
* @return true if the message is expunged, false otherwise
*/
virtual const bool isExpunged() const = 0;
/** Possible flags for a message.
*/
enum Flags
{
FLAG_SEEN = (1 << 0), /**< Message has been seen. */
FLAG_RECENT = (1 << 1), /**< Message has been recently received. */
FLAG_DELETED = (1 << 2), /**< Message is marked for deletion. */
FLAG_REPLIED = (1 << 3), /**< User replied to this message. */
FLAG_MARKED = (1 << 4), /**< Used-defined flag. */
FLAG_PASSED = (1 << 5), /**< Message has been resent/forwarded/bounced. */
FLAG_UNDEFINED = 9999 /**< Used internally (this should not be returned
by the flags() function). */
};
/** Methods for setting the flags.
*/
enum FlagsModes
{
FLAG_MODE_SET, /**< Set (replace) the flags. */
FLAG_MODE_ADD, /**< Add the flags. */
FLAG_MODE_REMOVE /**< Remove the flags. */
};
/** Return the flags of this message.
*
* @return flags of the message
*/
virtual const int getFlags() const = 0;
/** Set the flags of this message.
*
* @param flags set of flags (see Flags)
* @param mode indicate how to treat old and new flags (see FlagsModes)
*/
virtual void setFlags(const int flags, const int mode = FLAG_MODE_SET) = 0;
/** Extract the whole message data (header + contents).
*
* \warning Partial fetch might not be supported by the underlying protocol.
*
* @param os output stream in which to write message data
* @param progress progression listener, or NULL if not used
* @param start index of the first byte to retrieve (used for partial fetch)
* @param length number of bytes to retrieve (used for partial fetch)
* @param peek if true, try not to mark the message as read. This may not
* be supported by the protocol (IMAP supports this), but it will NOT throw
* an exception if not supported.
*/
virtual void extract(utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const = 0;
/** Extract the specified MIME part of the message (header + contents).
*
* \warning Partial fetch might not be supported by the underlying protocol.
*
* @param p part to extract
* @param os output stream in which to write part data
* @param progress progression listener, or NULL if not used
* @param start index of the first byte to retrieve (used for partial fetch)
* @param length number of bytes to retrieve (used for partial fetch)
* @param peek if true, try not to mark the message as read. This may not
* be supported by the protocol (IMAP supports this), but it will NOT throw
* an exception if not supported.
*/
virtual void extractPart(const part& p, utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const = 0;
/** Fetch the MIME header for the specified part.
*
* @param p the part for which to fetch the header
*/
virtual void fetchPartHeader(part& p) = 0;
};
} // net
} // vmime
#endif // VMIME_NET_MESSAGE_HPP_INCLUDED

View File

@ -0,0 +1,148 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
#define VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
#include <vector>
#include <map>
#include "vmime/config.hpp"
#include "vmime/types.hpp"
#include "vmime/net/folder.hpp"
namespace vmime {
namespace net {
namespace pop3 {
class POP3Store;
class POP3Message;
/** POP3 folder implementation.
*/
class POP3Folder : public folder
{
private:
friend class POP3Store;
friend class POP3Message;
friend class vmime::creator; // vmime::create <POP3Folder>
POP3Folder(const folder::path& path, POP3Store* store);
POP3Folder(const POP3Folder&) : folder() { }
~POP3Folder();
public:
const int getMode() const;
const int getType();
const int getFlags();
const folder::path::component getName() const;
const folder::path getFullPath() const;
void open(const int mode, bool failIfModeIsNotAvailable = false);
void close(const bool expunge);
void create(const int type);
const bool exists();
const bool isOpen() const;
ref <message> getMessage(const int num);
std::vector <ref <message> > getMessages(const int from = 1, const int to = -1);
std::vector <ref <message> > getMessages(const std::vector <int>& nums);
const int getMessageCount();
ref <folder> getFolder(const folder::path::component& name);
std::vector <ref <folder> > getFolders(const bool recursive = false);
void rename(const folder::path& newPath);
void deleteMessage(const int num);
void deleteMessages(const int from = 1, const int to = -1);
void deleteMessages(const std::vector <int>& nums);
void setMessageFlags(const int from, const int to, const int flags, const int mode = message::FLAG_MODE_SET);
void setMessageFlags(const std::vector <int>& nums, const int flags, const int mode = message::FLAG_MODE_SET);
void addMessage(ref <vmime::message> msg, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL);
void addMessage(utility::inputStream& is, const int size, const int flags = message::FLAG_UNDEFINED, vmime::datetime* date = NULL, utility::progressionListener* progress = NULL);
void copyMessage(const folder::path& dest, const int num);
void copyMessages(const folder::path& dest, const int from = 1, const int to = -1);
void copyMessages(const folder::path& dest, const std::vector <int>& nums);
void status(int& count, int& unseen);
void expunge();
ref <folder> getParent();
weak_ref <const store> getStore() const;
weak_ref <store> getStore();
void fetchMessages(std::vector <ref <message> >& msg, const int options, utility::progressionListener* progress = NULL);
void fetchMessage(ref <message> msg, const int options);
const int getFetchCapabilities() const;
private:
void registerMessage(POP3Message* msg);
void unregisterMessage(POP3Message* msg);
void onStoreDisconnected();
void onClose();
void parseMultiListOrUidlResponse(const string& response, std::map <int, string>& result);
POP3Store* m_store;
folder::path m_path;
folder::path::component m_name;
int m_mode;
bool m_open;
int m_messageCount;
typedef std::map <POP3Message*, int> MessageMap;
MessageMap m_messages;
};
} // pop3
} // net
} // vmime
#endif // VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED

View File

@ -0,0 +1,98 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
#define VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
#include "vmime/config.hpp"
#include "vmime/net/message.hpp"
#include "vmime/net/folder.hpp"
namespace vmime {
namespace net {
namespace pop3 {
class POP3Folder;
/** POP3 message implementation.
*/
class POP3Message : public message
{
private:
friend class POP3Folder;
friend class vmime::creator; // vmime::create <POP3Message>
POP3Message(POP3Folder* folder, const int num);
POP3Message(const POP3Message&) : message() { }
~POP3Message();
public:
const int getNumber() const;
const uid getUniqueId() const;
const int getSize() const;
const bool isExpunged() const;
const structure& getStructure() const;
structure& getStructure();
ref <const header> getHeader() const;
const int getFlags() const;
void setFlags(const int flags, const int mode = FLAG_MODE_SET);
void extract(utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const;
void extractPart(const part& p, utility::outputStream& os, utility::progressionListener* progress = NULL, const int start = 0, const int length = -1, const bool peek = false) const;
void fetchPartHeader(part& p);
private:
void fetch(POP3Folder* folder, const int options);
void onFolderClosed();
POP3Folder* m_folder;
int m_num;
uid m_uid;
int m_size;
bool m_deleted;
ref <header> m_header;
};
} // pop3
} // net
} // vmime
#endif // VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED

View File

@ -0,0 +1,138 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
#define VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
#include "vmime/config.hpp"
#include "vmime/net/store.hpp"
#include "vmime/net/socket.hpp"
#include "vmime/net/timeoutHandler.hpp"
#include "vmime/utility/stream.hpp"
namespace vmime {
namespace net {
namespace pop3 {
class POP3Folder;
/** POP3 store service.
*/
class POP3Store : public store
{
friend class POP3Folder;
friend class POP3Message;
public:
POP3Store(ref <session> sess, ref <authenticator> auth);
~POP3Store();
const string getProtocolName() const;
ref <folder> getDefaultFolder();
ref <folder> getRootFolder();
ref <folder> getFolder(const folder::path& path);
const bool isValidFolderName(const folder::path::component& name) const;
static const serviceInfos& getInfosInstance();
const serviceInfos& getInfos() const;
void connect();
const bool isConnected() const;
void disconnect();
void noop();
const int getCapabilities() const;
private:
static const bool isSuccessResponse(const string& buffer);
static const bool stripFirstLine(const string& buffer, string& result, string* firstLine = NULL);
static void stripResponseCode(const string& buffer, string& result);
void sendRequest(const string& buffer, const bool end = true);
void readResponse(string& buffer, const bool multiLine, utility::progressionListener* progress = NULL);
void readResponse(utility::outputStream& os, utility::progressionListener* progress = NULL, const int predictedSize = 0);
static const bool checkTerminator(string& buffer, const bool multiLine);
static const bool checkOneTerminator(string& buffer, const string& term);
void internalDisconnect();
void registerFolder(POP3Folder* folder);
void unregisterFolder(POP3Folder* folder);
std::list <POP3Folder*> m_folders;
ref <socket> m_socket;
bool m_authentified;
ref <timeoutHandler> m_timeoutHandler;
// Service infos
class _infos : public serviceInfos
{
public:
struct props
{
// POP3-specific options
serviceInfos::property PROPERTY_OPTIONS_APOP;
serviceInfos::property PROPERTY_OPTIONS_APOP_FALLBACK;
// Common properties
serviceInfos::property PROPERTY_AUTH_USERNAME;
serviceInfos::property PROPERTY_AUTH_PASSWORD;
serviceInfos::property PROPERTY_SERVER_ADDRESS;
serviceInfos::property PROPERTY_SERVER_PORT;
serviceInfos::property PROPERTY_SERVER_SOCKETFACTORY;
serviceInfos::property PROPERTY_TIMEOUT_FACTORY;
};
const props& getProperties() const;
const string getPropertyPrefix() const;
const std::vector <serviceInfos::property> getAvailableProperties() const;
};
static _infos sm_infos;
};
} // pop3
} // net
} // vmime
#endif // VMIME_NET_POP3_POP3STORE_HPP_INCLUDED

View File

@ -0,0 +1,103 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
#define VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
#include "vmime/config.hpp"
#include "vmime/net/transport.hpp"
#include "vmime/net/socket.hpp"
#include "vmime/net/timeoutHandler.hpp"
#if VMIME_BUILTIN_PLATFORM_POSIX
namespace vmime {
namespace net {
namespace sendmail {
/** Sendmail local transport service.
*/
class sendmailTransport : public transport
{
public:
sendmailTransport(ref <session> sess, ref <authenticator> auth);
~sendmailTransport();
const string getProtocolName() const;
static const serviceInfos& getInfosInstance();
const serviceInfos& getInfos() const;
void connect();
const bool isConnected() const;
void disconnect();
void noop();
void send(const mailbox& expeditor, const mailboxList& recipients, utility::inputStream& is, const utility::stream::size_type size, utility::progressionListener* progress = NULL);
private:
void internalDisconnect();
void internalSend(const std::vector <string> args, utility::inputStream& is,
const utility::stream::size_type size, utility::progressionListener* progress);
string m_sendmailPath;
bool m_connected;
// Service infos
class _infos : public serviceInfos
{
public:
struct props
{
serviceInfos::property PROPERTY_BINPATH;
};
const props& getProperties() const;
const string getPropertyPrefix() const;
const std::vector <serviceInfos::property> getAvailableProperties() const;
};
static _infos sm_infos;
};
} // sendmail
} // net
} // vmime
#endif // VMIME_BUILTIN_PLATFORM_POSIX
#endif // VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED

161
vmime/net/service.hpp Normal file
View File

@ -0,0 +1,161 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SERVICE_HPP_INCLUDED
#define VMIME_NET_SERVICE_HPP_INCLUDED
#include "vmime/types.hpp"
#include "vmime/net/session.hpp"
#include "vmime/net/authenticator.hpp"
#include "vmime/net/serviceFactory.hpp"
#include "vmime/net/serviceInfos.hpp"
#include "vmime/utility/progressionListener.hpp"
namespace vmime {
namespace net {
/** Base class for messaging services.
*/
class service : public object
{
protected:
service(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth);
public:
virtual ~service();
// Possible service types
enum Type
{
TYPE_STORE = 0, /**< The service is a message store. */
TYPE_TRANSPORT /**< The service sends messages. */
};
/** Return the type of service.
*
* @return type of service
*/
virtual const Type getType() const = 0;
/** Return the protocol name of this service.
*
* @return protocol name
*/
virtual const string getProtocolName() const = 0;
/** Return the session object associated with this service instance.
*
* @return session object
*/
ref <const session> getSession() const;
/** Return the session object associated with this service instance.
*
* @return session object
*/
ref <session> getSession();
/** Return information about this service.
*
* @return information about the service
*/
virtual const serviceInfos& getInfos() const = 0;
/** Connect to service.
*/
virtual void connect() = 0;
/** Disconnect from service.
*/
virtual void disconnect() = 0;
/** Test whether this service is connected.
*
* @return true if the service is connected, false otherwise
*/
virtual const bool isConnected() const = 0;
/** Do nothing but ensure the server do not disconnect (for
* example, this can reset the auto-logout timer on the
* server, if one exists).
*/
virtual void noop() = 0;
/** Return the authenticator object used with this service instance.
*
* @return authenticator object
*/
ref <const authenticator> getAuthenticator() const;
/** Return the authenticator object used with this service instance.
*
* @return authenticator object
*/
ref <authenticator> getAuthenticator();
/** Set a property for this service (service prefix is added automatically).
*
* WARNING: this sets the property on the session object, so all service
* instances created with the session object will inherit the property.
*
* @param name property name
* @param value property value
*/
template <typename TYPE>
void setProperty(const string& name, const TYPE& value)
{
m_session->getProperties()[getInfos().getPropertyPrefix() + name] = value;
}
#ifndef VMIME_BUILDING_DOC
// Basic service registerer
template <class S>
class initializer
{
public:
initializer(const string& protocol)
{
serviceFactory::getInstance()->
template registerServiceByProtocol <S>(protocol);
}
};
#endif // VMIME_BUILDING_DOC
private:
ref <session> m_session;
ref <authenticator> m_auth;
};
} // net
} // vmime
#endif // VMIME_NET_SERVICE_HPP_INCLUDED

View File

@ -0,0 +1,188 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
#define VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
#include <map>
#include "vmime/types.hpp"
#include "vmime/base.hpp"
#include "vmime/utility/stringUtils.hpp"
#include "vmime/utility/url.hpp"
#include "vmime/net/serviceInfos.hpp"
#include "vmime/net/authenticator.hpp"
#include "vmime/net/timeoutHandler.hpp"
#include "vmime/utility/progressionListener.hpp"
namespace vmime {
namespace net {
class service;
class session;
/** A factory to create 'service' objects for a specified protocol.
*/
class serviceFactory
{
private:
serviceFactory();
~serviceFactory();
public:
static serviceFactory* getInstance();
/** Information about a registered service. */
class registeredService : public object
{
friend class serviceFactory;
protected:
virtual ~registeredService() { }
public:
virtual ref <service> create(ref <session> sess, ref <authenticator> auth) const = 0;
virtual const string& getName() const = 0;
virtual const serviceInfos& getInfos() const = 0;
};
private:
template <class S>
class registeredServiceImpl : public registeredService
{
friend class serviceFactory;
friend class vmime::creator;
protected:
registeredServiceImpl(const string& name)
: m_name(name), m_servInfos(S::getInfosInstance())
{
}
public:
ref <service> create(ref <session> sess, ref <authenticator> auth) const
{
return vmime::create <S>(sess, auth);
}
const serviceInfos& getInfos() const
{
return (m_servInfos);
}
const string& getName() const
{
return (m_name);
}
private:
const string m_name;
const serviceInfos& m_servInfos;
};
std::vector <ref <registeredService> > m_services;
public:
/** Register a new service by its protocol name.
*
* @param protocol protocol name
*/
template <class S>
void registerServiceByProtocol(const string& protocol)
{
const string name = utility::stringUtils::toLower(protocol);
m_services.push_back(vmime::create <registeredServiceImpl <S> >(name));
}
/** Create a new service instance from a protocol name.
*
* @param sess session
* @param protocol protocol name (eg. "pop3")
* @param auth authenticator used to provide credentials (can be NULL if not used)
* @return a new service instance for the specified protocol
* @throw exceptions::no_service_available if no service is registered
* for this protocol
*/
ref <service> create(ref <session> sess, const string& protocol, ref <authenticator> auth = NULL);
/** Create a new service instance from a URL.
*
* @param sess session
* @param u full URL with at least protocol and server (you can also specify
* port, username and password)
* @param auth authenticator used to provide credentials (can be NULL if not used)
* @return a new service instance for the specified protocol
* @throw exceptions::no_service_available if no service is registered
* for this protocol
*/
ref <service> create(ref <session> sess, const utility::url& u, ref <authenticator> auth = NULL);
/** Return information about a registered protocol.
*
* @param protocol protocol name
* @return information about this protocol
* @throw exceptions::no_service_available if no service is registered
* for this protocol
*/
ref <const registeredService> getServiceByProtocol(const string& protocol) const;
/** Return the number of registered services.
*
* @return number of registered services
*/
const int getServiceCount() const;
/** Return the registered service at the specified position.
*
* @param pos position of the registered service to return
* @return registered service at the specified position
*/
ref <const registeredService> getServiceAt(const int pos) const;
/** Return a list of all registered services.
*
* @return list of registered services
*/
const std::vector <ref <const registeredService> > getServiceList() const;
};
} // net
} // vmime
#endif // VMIME_NET_SERVICEFACTORY_HPP_INCLUDED

228
vmime/net/serviceInfos.hpp Normal file
View File

@ -0,0 +1,228 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SERVICEINFOS_HPP_INCLUDED
#define VMIME_NET_SERVICEINFOS_HPP_INCLUDED
#include <vector>
#include "vmime/types.hpp"
#include "vmime/net/session.hpp"
namespace vmime {
namespace net {
/** Stores information about a messaging service.
*/
class serviceInfos
{
friend class serviceFactory;
protected:
serviceInfos();
serviceInfos(const serviceInfos&);
private:
serviceInfos& operator=(const serviceInfos&);
public:
virtual ~serviceInfos();
/** A service property.
*/
class property
{
public:
/** The common property 'server.address' which is
* the host name or the IP address of the server. */
static const property SERVER_ADDRESS;
/** The common property 'server.port' which is
* the port used to connect to the server. */
static const property SERVER_PORT;
/** The common property 'server.rootpath' which is
* the full path of the folder on the server (for
* maildir, this is the local filesystem directory). */
static const property SERVER_ROOTPATH;
/** The common property 'server.socket-factory' used
* to indicate which factory to use to instanciate
* new socket objects. */
static const property SERVER_SOCKETFACTORY;
/** The common property 'auth.username' which is the
* username used to authenticate with the server. */
static const property AUTH_USERNAME;
/** The common property 'auth.password' which is the
* password used to authenticate with the server. */
static const property AUTH_PASSWORD;
/** The common property 'timeout.factory' used to
* specify which factory to use to instanciate
* time-out handler objects. If none is specified,
* no time-out handler is used. */
static const property TIMEOUT_FACTORY;
/** Value types.
*/
enum Types
{
TYPE_INTEGER, /*< Integer number. */
TYPE_STRING, /*< Character string. */
TYPE_BOOL, /*< Boolean (true or false). */
TYPE_DEFAULT = TYPE_STRING
};
/** Property flags.
*/
enum Flags
{
FLAG_NONE = 0, /*< No flags. */
FLAG_REQUIRED = (1 << 0), /*< The property must be valued. */
FLAG_HIDDEN = (1 << 1), /*< The property should not be shown
to the user but can be modified. */
FLAG_DEFAULT = FLAG_NONE /*< Default flags. */
};
/** Construct a new property.
*
* @param name property name
* @param type value type
* @param defaultValue default value
* @param flags property attributes
*/
property(const string& name, const Types type, const string& defaultValue = "", const int flags = FLAG_DEFAULT);
/** Construct a new property from an existing property.
*
* @param p source property
* @param addFlags flags to add
* @param removeFlags flags to remove
*/
property(const property& p, const int addFlags = FLAG_NONE, const int removeFlags = FLAG_NONE);
/** Construct a new property from an existing property.
*
* @param p source property
* @param newDefaultValue new default value
* @param addFlags flags to add
* @param removeFlags flags to remove
*/
property(const property& p, const string& newDefaultValue, const int addFlags = FLAG_NONE, const int removeFlags = FLAG_NONE);
property& operator=(const property& p);
/** Return the name of the property.
*
* @return property name
*/
const string& getName() const;
/** Return the default value of the property or
* an empty string if there is no default value.
*
* @return default value for the property
*/
const string& getDefaultValue() const;
/** Return the value type of the property.
*
* @return property value type
*/
const Types getType() const;
/** Return the attributes of the property (see
* serviceInfos::property::Types constants).
*
* @return property attributes
*/
const int getFlags() const;
private:
string m_name;
string m_defaultValue;
Types m_type;
int m_flags;
};
/** Return the property prefix used by this service.
* Use this to set/get properties in the session object.
*
* @return property prefix
*/
virtual const string getPropertyPrefix() const = 0;
/** Return a list of available properties for this service.
*
* @return list of properties
*/
virtual const std::vector <property> getAvailableProperties() const = 0;
/** Helper function to retrieve the value of a property.
*
* @param s session object
* @param p property to retrieve
* @throw exceptions::no_such_property if the property does not exist
* and has the flag property::FLAG_REQUIRED
* @return value of the property
*/
template <typename TYPE>
const TYPE getPropertyValue(ref <session> s, const property& p) const
{
if (p.getFlags() & property::FLAG_REQUIRED)
return s->getProperties()[getPropertyPrefix() + p.getName()].template getValue <TYPE>();
return s->getProperties().template getProperty <TYPE>(getPropertyPrefix() + p.getName(),
propertySet::valueFromString <TYPE>(p.getDefaultValue()));
}
/** Helper function to test if the specified property is set in
* the session object.
*
* @param s session object
* @param p property to test
* @return true if the property is set, false otherwise
*/
const bool hasProperty(ref <session> s, const property& p) const;
};
} // net
} // vmime
#endif // VMIME_NET_SERVICEINFOS_HPP_INCLUDED

135
vmime/net/session.hpp Normal file
View File

@ -0,0 +1,135 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SESSION_HPP_INCLUDED
#define VMIME_NET_SESSION_HPP_INCLUDED
#include "vmime/net/authenticator.hpp"
#include "vmime/utility/url.hpp"
#include "vmime/propertySet.hpp"
namespace vmime {
namespace net {
class store;
class transport;
/** An object that contains all the information needed
* for connection to a service.
*/
class session : public object
{
public:
session();
session(const session& sess);
session(const propertySet& props);
virtual ~session();
/** Return a transport service instance for the protocol specified
* in the session properties.
*
* The property "transport.protocol" specify the protocol to use.
*
* @param auth authenticator object to use for the new transport service. If
* NULL, a default one is used. The default authenticator simply return user
* credentials by reading the session properties "auth.username" and "auth.password".
* @return a new transport service
*/
ref <transport> getTransport(ref <authenticator> auth = NULL);
/** Return a transport service instance for the specified protocol.
*
* @param protocol transport protocol to use (eg. "smtp")
* @param auth authenticator object to use for the new transport service. If
* NULL, a default one is used. The default authenticator simply return user
* credentials by reading the session properties "auth.username" and "auth.password".
* @return a new transport service
*/
ref <transport> getTransport(const string& protocol, ref <authenticator> auth = NULL);
/** Return a transport service instance for the specified URL.
*
* @param url full URL with at least the protocol to use (eg: "smtp://myserver.com/")
* @param auth authenticator object to use for the new transport service. If
* NULL, a default one is used. The default authenticator simply return user
* credentials by reading the session properties "auth.username" and "auth.password".
* @return a new transport service
*/
ref <transport> getTransport(const utility::url& url, ref <authenticator> auth = NULL);
/** Return a transport service instance for the protocol specified
* in the session properties.
*
* The property "store.protocol" specify the protocol to use.
*
* @param auth authenticator object to use for the new store service. If
* NULL, a default one is used. The default authenticator simply return user
* credentials by reading the session properties "auth.username" and "auth.password".
* @return a new store service
*/
ref <store> getStore(ref <authenticator> auth = NULL);
/** Return a store service instance for the specified protocol.
*
* @param protocol store protocol to use (eg. "imap")
* @param auth authenticator object to use for the new store service. If
* NULL, a default one is used. The default authenticator simply return user
* credentials by reading the session properties "auth.username" and "auth.password".
* @return a new store service
*/
ref <store> getStore(const string& protocol, ref <authenticator> auth = NULL);
/** Return a store service instance for the specified URL.
*
* @param url full URL with at least the protocol to use (eg: "imap://username:password@myserver.com/")
* @param auth authenticator object to use for the new store service. If
* NULL, a default one is used. The default authenticator simply return user
* credentials by reading the session properties "auth.username" and "auth.password".
* @return a new store service
*/
ref <store> getStore(const utility::url& url, ref <authenticator> auth = NULL);
/** Properties for the session and for the services.
*/
const propertySet& getProperties() const;
/** Properties for the session and for the services.
*/
propertySet& getProperties();
private:
propertySet m_props;
};
} // net
} // vmime
#endif // VMIME_NET_SESSION_HPP_INCLUDED

View File

@ -0,0 +1,62 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SIMPLEAUTHENTICATOR_HPP_INCLUDED
#define VMIME_NET_SIMPLEAUTHENTICATOR_HPP_INCLUDED
#include "vmime/net/authenticator.hpp"
namespace vmime {
namespace net {
/** Basic implementation for an authenticator.
*/
class simpleAuthenticator : public authenticator
{
public:
simpleAuthenticator();
simpleAuthenticator(const string& username, const string& password);
public:
const string& getUsername() const;
void setUsername(const string& username);
const string& getPassword() const;
void setPassword(const string& password);
private:
string m_username;
string m_password;
const authenticationInfos getAuthInfos() const;
};
} // net
} // vmime
#endif // VMIME_NET_SIMPLEAUTHENTICATOR_HPP_INCLUDED

View File

@ -0,0 +1,113 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
#define VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
#include "vmime/config.hpp"
#include "vmime/net/transport.hpp"
#include "vmime/net/socket.hpp"
#include "vmime/net/timeoutHandler.hpp"
namespace vmime {
namespace net {
namespace smtp {
/** SMTP transport service.
*/
class SMTPTransport : public transport
{
public:
SMTPTransport(ref <session> sess, ref <authenticator> auth);
~SMTPTransport();
const string getProtocolName() const;
static const serviceInfos& getInfosInstance();
const serviceInfos& getInfos() const;
void connect();
const bool isConnected() const;
void disconnect();
void noop();
void send(const mailbox& expeditor, const mailboxList& recipients, utility::inputStream& is, const utility::stream::size_type size, utility::progressionListener* progress = NULL);
private:
static const int responseCode(const string& response);
static const string responseText(const string& response);
void sendRequest(const string& buffer, const bool end = true);
void readResponse(string& buffer);
void internalDisconnect();
ref <socket> m_socket;
bool m_authentified;
bool m_extendedSMTP;
ref <timeoutHandler> m_timeoutHandler;
// Service infos
class _infos : public serviceInfos
{
public:
struct props
{
// SMTP-specific options
serviceInfos::property PROPERTY_OPTIONS_NEEDAUTH;
// Common properties
serviceInfos::property PROPERTY_AUTH_USERNAME;
serviceInfos::property PROPERTY_AUTH_PASSWORD;
serviceInfos::property PROPERTY_SERVER_ADDRESS;
serviceInfos::property PROPERTY_SERVER_PORT;
serviceInfos::property PROPERTY_SERVER_SOCKETFACTORY;
serviceInfos::property PROPERTY_TIMEOUT_FACTORY;
};
const props& getProperties() const;
const string getPropertyPrefix() const;
const std::vector <serviceInfos::property> getAvailableProperties() const;
};
static _infos sm_infos;
};
} // smtp
} // net
} // vmime
#endif // VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED

112
vmime/net/socket.hpp Normal file
View File

@ -0,0 +1,112 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_SOCKET_HPP_INCLUDED
#define VMIME_NET_SOCKET_HPP_INCLUDED
#include "vmime/base.hpp"
namespace vmime {
namespace net {
/** Interface for connecting to servers.
*/
class socket : public object
{
public:
virtual ~socket() { }
/** Connect to the specified address and port.
*
* @param address server address (this can be a full qualified domain name
* or an IP address, doesn't matter)
* @param port server port
*/
virtual void connect(const string& address, const port_t port) = 0;
/** Disconnect from the server.
*/
virtual void disconnect() = 0;
/** Test whether this socket is connected.
*
* @return true if the socket is connected, false otherwise
*/
virtual const bool isConnected() const = 0;
/** Receive (text) data from the socket.
*
* @param buffer buffer in which to write received data
*/
virtual void receive(string& buffer) = 0;
/** Receive (raw) data from the socket.
*
* @param buffer buffer in which to write received data
* @param count maximum number of bytes to receive (size of buffer)
* @return number of bytes received/written into output buffer
*/
virtual const int receiveRaw(char* buffer, const int count) = 0;
/** Send (text) data to the socket.
*
* @param buffer data to send
*/
virtual void send(const string& buffer) = 0;
/** Send (raw) data to the socket.
*
* @param buffer data to send
* @param count number of bytes to send (size of buffer)
*/
virtual void sendRaw(const char* buffer, const int count) = 0;
protected:
socket() { }
private:
socket(const socket&) : object() { }
};
/** A class to create 'socket' objects.
*/
class socketFactory
{
public:
virtual ~socketFactory() { }
virtual ref <socket> create() = 0;
};
} // net
} // vmime
#endif // VMIME_NET_SOCKET_HPP_INCLUDED

102
vmime/net/store.hpp Normal file
View File

@ -0,0 +1,102 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_STORE_HPP_INCLUDED
#define VMIME_NET_STORE_HPP_INCLUDED
#include "vmime/net/service.hpp"
#include "vmime/net/folder.hpp"
namespace vmime {
namespace net {
/** A store service.
* Encapsulate protocols that provide access to user's mail drop.
*/
class store : public service
{
protected:
store(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth)
: service(sess, infos, auth) { }
public:
/** Return the default folder. This is protocol dependant
* and usually is the INBOX folder.
*
* @return default folder
*/
virtual ref <folder> getDefaultFolder() = 0;
/** Return the root folder. This is protocol dependant
* and usually is the user's mail drop root folder.
*
* @return root folder
*/
virtual ref <folder> getRootFolder() = 0;
/** Return the folder specified by the path.
*
* @param path absolute folder path
* @return folder at the specified path
*/
virtual ref <folder> getFolder(const folder::path& path) = 0;
/** Test whether the specified folder name is a syntactically
* a valid name.
*
* @return true if the specified folder name is valid, false otherwise
*/
virtual const bool isValidFolderName(const folder::path::component& name) const = 0;
/** Store capabilities. */
enum Capabilities
{
CAPABILITY_CREATE_FOLDER = (1 << 0), /**< Can create folders. */
CAPABILITY_RENAME_FOLDER = (1 << 1), /**< Can rename folders. */
CAPABILITY_ADD_MESSAGE = (1 << 2), /**< Can append message to folders. */
CAPABILITY_COPY_MESSAGE = (1 << 3), /**< Can copy messages from a folder to another one. */
CAPABILITY_DELETE_MESSAGE = (1 << 4), /**< Can delete messages. */
CAPABILITY_PARTIAL_FETCH = (1 << 5), /**< Is partial fetch supported? */
CAPABILITY_MESSAGE_FLAGS = (1 << 6), /**< Can set flags on messages. */
CAPABILITY_EXTRACT_PART = (1 << 7) /**< Can extract a specific part of the message. */
};
/** Return the features supported by this service. This is
* a combination of store::CAPABILITY_xxx flags.
*
* @return features supported by this service
*/
virtual const int getCapabilities() const = 0;
const Type getType() const { return (TYPE_STORE); }
};
} // net
} // vmime
#endif // VMIME_NET_STORE_HPP_INCLUDED

View File

@ -0,0 +1,77 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
#define VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
#include "vmime/types.hpp"
namespace vmime {
namespace net {
/** A class to manage time-out in messaging services.
*/
class timeoutHandler : public object
{
public:
virtual ~timeoutHandler() { }
/** Called to test if the time limit has been reached.
*
* @return true if the time-out delay is elapsed
*/
virtual const bool isTimeOut() = 0;
/** Called to reset the time-out counter.
*/
virtual void resetTimeOut() = 0;
/** Called when the time limit has been reached (when
* isTimeOut() returned true).
*
* @return true to continue (and reset the time-out)
* or false to cancel the current operation
*/
virtual const bool handleTimeOut() = 0;
};
/** A class to create 'timeoutHandler' objects.
*/
class timeoutHandlerFactory
{
public:
virtual ~timeoutHandlerFactory() { }
virtual ref <timeoutHandler> create() = 0;
};
} // net
} // vmime
#endif // VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED

75
vmime/net/transport.hpp Normal file
View File

@ -0,0 +1,75 @@
//
// VMime library (http://www.vmime.org)
// Copyright (C) 2002-2005 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#ifndef VMIME_NET_TRANSPORT_HPP_INCLUDED
#define VMIME_NET_TRANSPORT_HPP_INCLUDED
#include "vmime/net/service.hpp"
#include "vmime/utility/stream.hpp"
namespace vmime {
class message;
class mailbox;
class mailboxList;
namespace net {
/** A transport service.
* Encapsulate protocols that can send messages.
*/
class transport : public service
{
protected:
transport(ref <session> sess, const serviceInfos& infos, ref <authenticator> auth);
public:
/** Send a message over this transport service.
*
* @param msg message to send
* @param progress progression listener, or NULL if not used
*/
virtual void send(ref <vmime::message> msg, utility::progressionListener* progress = NULL);
/** Send a message over this transport service.
*
* @param expeditor expeditor mailbox
* @param recipients list of recipient mailboxes
* @param is input stream provding message data (header + body)
* @param size size of the message data
* @param progress progression listener, or NULL if not used
*/
virtual void send(const mailbox& expeditor, const mailboxList& recipients, utility::inputStream& is, const utility::stream::size_type size, utility::progressionListener* progress = NULL) = 0;
const Type getType() const;
};
} // net
} // vmime
#endif // VMIME_NET_TRANSPORT_HPP_INCLUDED

View File

@ -27,8 +27,8 @@
#include "vmime/charset.hpp" #include "vmime/charset.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
#include "vmime/messaging/socket.hpp" #include "vmime/net/socket.hpp"
#include "vmime/messaging/timeoutHandler.hpp" #include "vmime/net/timeoutHandler.hpp"
#endif #endif
#if VMIME_HAVE_FILESYSTEM_FEATURES #if VMIME_HAVE_FILESYSTEM_FEATURES
@ -110,7 +110,7 @@ public:
* session object * session object
* @return socket factory * @return socket factory
*/ */
virtual messaging::socketFactory* getSocketFactory(const string& name = "default") const = 0; virtual net::socketFactory* getSocketFactory(const string& name = "default") const = 0;
/** Return a pointer to a timeout-handler factory for the specified name. /** Return a pointer to a timeout-handler factory for the specified name.
* The returned object will not be deleted by VMime, so it can be a * The returned object will not be deleted by VMime, so it can be a
@ -124,7 +124,7 @@ public:
* @param name time-out type name * @param name time-out type name
* @return time-out factory * @return time-out factory
*/ */
virtual messaging::timeoutHandlerFactory* getTimeoutHandlerFactory(const string& name = "default") const = 0; virtual net::timeoutHandlerFactory* getTimeoutHandlerFactory(const string& name = "default") const = 0;
#endif #endif
#if VMIME_HAVE_FILESYSTEM_FEATURES #if VMIME_HAVE_FILESYSTEM_FEATURES
/** Return a pointer to a factory that creates file-system objects. /** Return a pointer to a factory that creates file-system objects.

View File

@ -57,9 +57,9 @@ public:
const unsigned int getProcessId() const; const unsigned int getProcessId() const;
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
vmime::messaging::socketFactory* getSocketFactory(const vmime::string& name) const; vmime::net::socketFactory* getSocketFactory(const vmime::string& name) const;
vmime::messaging::timeoutHandlerFactory* getTimeoutHandlerFactory(const vmime::string& name) const; vmime::net::timeoutHandlerFactory* getTimeoutHandlerFactory(const vmime::string& name) const;
#endif #endif
#if VMIME_HAVE_FILESYSTEM_FEATURES #if VMIME_HAVE_FILESYSTEM_FEATURES

View File

@ -21,7 +21,7 @@
#define VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED #define VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED
#include "vmime/messaging/socket.hpp" #include "vmime/net/socket.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
@ -32,7 +32,7 @@ namespace platforms {
namespace posix { namespace posix {
class posixSocket : public vmime::messaging::socket class posixSocket : public vmime::net::socket
{ {
public: public:
@ -57,11 +57,11 @@ private:
class posixSocketFactory : public vmime::messaging::socketFactory class posixSocketFactory : public vmime::net::socketFactory
{ {
public: public:
ref <vmime::messaging::socket> create(); ref <vmime::net::socket> create();
}; };

View File

@ -56,9 +56,9 @@ public:
const unsigned int getProcessId() const; const unsigned int getProcessId() const;
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
vmime::messaging::socketFactory* getSocketFactory(const vmime::string& name) const; vmime::net::socketFactory* getSocketFactory(const vmime::string& name) const;
vmime::messaging::timeoutHandlerFactory* getTimeoutHandlerFactory(const vmime::string& name) const; vmime::net::timeoutHandlerFactory* getTimeoutHandlerFactory(const vmime::string& name) const;
#endif #endif
#if VMIME_HAVE_FILESYSTEM_FEATURES #if VMIME_HAVE_FILESYSTEM_FEATURES

View File

@ -22,7 +22,7 @@
#include <winsock2.h> #include <winsock2.h>
#include "vmime/messaging/socket.hpp" #include "vmime/net/socket.hpp"
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
@ -33,7 +33,7 @@ namespace platforms {
namespace windows { namespace windows {
class windowsSocket : public vmime::messaging::socket class windowsSocket : public vmime::net::socket
{ {
public: public:
windowsSocket(); windowsSocket();
@ -59,11 +59,11 @@ private:
class windowsSocketFactory : public vmime::messaging::socketFactory class windowsSocketFactory : public vmime::net::socketFactory
{ {
public: public:
ref <vmime::messaging::socket> create(); ref <vmime::net::socket> create();
}; };

View File

@ -47,6 +47,10 @@ namespace vmime
using vmime::utility::null_ref; using vmime::utility::null_ref;
extern const null_ref null; extern const null_ref null;
// For compatibility with versions <= 0.7.1 (deprecated)
namespace net { }
namespace messaging = net;
} }

View File

@ -33,9 +33,9 @@
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
namespace vmime { namespace vmime {
namespace messaging { namespace net {
class socket; // forward reference class socket; // forward reference
} // messaging } // net
} // vmime } // vmime
#endif #endif
@ -336,7 +336,7 @@ class outputStreamSocketAdapter : public outputStream
{ {
public: public:
outputStreamSocketAdapter(messaging::socket& sok); outputStreamSocketAdapter(net::socket& sok);
void write(const value_type* const data, const size_type count); void write(const value_type* const data, const size_type count);
@ -344,7 +344,7 @@ private:
outputStreamSocketAdapter(const outputStreamSocketAdapter&); outputStreamSocketAdapter(const outputStreamSocketAdapter&);
messaging::socket& m_socket; net::socket& m_socket;
}; };
@ -355,7 +355,7 @@ class inputStreamSocketAdapter : public inputStream
{ {
public: public:
inputStreamSocketAdapter(messaging::socket& sok); inputStreamSocketAdapter(net::socket& sok);
const bool eof() const; const bool eof() const;
void reset(); void reset();
@ -366,7 +366,7 @@ private:
inputStreamSocketAdapter(const inputStreamSocketAdapter&); inputStreamSocketAdapter(const inputStreamSocketAdapter&);
messaging::socket& m_socket; net::socket& m_socket;
}; };

View File

@ -88,19 +88,19 @@
// Messaging features // Messaging features
#if VMIME_HAVE_MESSAGING_FEATURES #if VMIME_HAVE_MESSAGING_FEATURES
#include "vmime/messaging/socket.hpp" #include "vmime/net/socket.hpp"
#include "vmime/messaging/service.hpp" #include "vmime/net/service.hpp"
#include "vmime/messaging/store.hpp" #include "vmime/net/store.hpp"
#include "vmime/messaging/transport.hpp" #include "vmime/net/transport.hpp"
#include "vmime/messaging/session.hpp" #include "vmime/net/session.hpp"
#include "vmime/messaging/authenticator.hpp" #include "vmime/net/authenticator.hpp"
#include "vmime/messaging/defaultAuthenticator.hpp" #include "vmime/net/defaultAuthenticator.hpp"
#include "vmime/messaging/simpleAuthenticator.hpp" #include "vmime/net/simpleAuthenticator.hpp"
#include "vmime/messaging/folder.hpp" #include "vmime/net/folder.hpp"
#include "vmime/messaging/message.hpp" #include "vmime/net/message.hpp"
#endif // VMIME_HAVE_MESSAGING_FEATURES #endif // VMIME_HAVE_MESSAGING_FEATURES