aboutsummaryrefslogtreecommitdiff
path: root/vmime-master/src/vmime/net
diff options
context:
space:
mode:
authorWojtek Kosior <wk@koszkonutek-tmp.pl.eu.org>2021-04-30 00:33:56 +0200
committerWojtek Kosior <wk@koszkonutek-tmp.pl.eu.org>2021-04-30 00:33:56 +0200
commitaa4d426b4d3527d7e166df1a05058c9a4a0f6683 (patch)
tree4ff17ce8b89a2321b9d0ed4bcfc37c447bcb6820 /vmime-master/src/vmime/net
downloadsmtps-and-pop3s-console-program-aa4d426b4d3527d7e166df1a05058c9a4a0f6683.tar.gz
smtps-and-pop3s-console-program-aa4d426b4d3527d7e166df1a05058c9a4a0f6683.zip
initial/final commitHEADmaster
Diffstat (limited to 'vmime-master/src/vmime/net')
-rw-r--r--vmime-master/src/vmime/net/builtinServices.inl76
-rw-r--r--vmime-master/src/vmime/net/connectionInfos.hpp68
-rw-r--r--vmime-master/src/vmime/net/defaultConnectionInfos.cpp60
-rw-r--r--vmime-master/src/vmime/net/defaultConnectionInfos.hpp66
-rw-r--r--vmime-master/src/vmime/net/defaultTimeoutHandler.cpp78
-rw-r--r--vmime-master/src/vmime/net/defaultTimeoutHandler.hpp80
-rw-r--r--vmime-master/src/vmime/net/dsnAttributes.cpp71
-rw-r--r--vmime-master/src/vmime/net/dsnAttributes.hpp114
-rw-r--r--vmime-master/src/vmime/net/events.cpp180
-rw-r--r--vmime-master/src/vmime/net/events.hpp276
-rw-r--r--vmime-master/src/vmime/net/fetchAttributes.cpp98
-rw-r--r--vmime-master/src/vmime/net/fetchAttributes.hpp140
-rw-r--r--vmime-master/src/vmime/net/folder.cpp134
-rw-r--r--vmime-master/src/vmime/net/folder.hpp440
-rw-r--r--vmime-master/src/vmime/net/folderAttributes.cpp122
-rw-r--r--vmime-master/src/vmime/net/folderAttributes.hpp177
-rw-r--r--vmime-master/src/vmime/net/folderStatus.hpp73
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPCommand.cpp437
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPCommand.hpp124
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPConnection.cpp886
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPConnection.hpp172
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolder.cpp1622
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolder.hpp230
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp292
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp123
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessage.cpp760
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessage.hpp200
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp225
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp108
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp227
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp95
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp94
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp75
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPParser.hpp4986
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPSStore.cpp82
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPSStore.hpp70
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp135
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp89
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPStore.cpp287
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPStore.hpp124
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPTag.cpp148
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPTag.hpp85
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPUtils.cpp854
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPUtils.hpp144
-rw-r--r--vmime-master/src/vmime/net/imap/imap.hpp35
-rw-r--r--vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp569
-rw-r--r--vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp127
-rw-r--r--vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp337
-rw-r--r--vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp115
-rw-r--r--vmime-master/src/vmime/net/maildir/maildir.hpp34
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolder.cpp1365
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolder.hpp211
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp88
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp75
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFormat.cpp104
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFormat.hpp192
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessage.cpp410
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessage.hpp137
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp178
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp106
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp104
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp82
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp76
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp69
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirStore.cpp294
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirStore.hpp123
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirUtils.cpp288
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirUtils.hpp160
-rw-r--r--vmime-master/src/vmime/net/message.cpp155
-rw-r--r--vmime-master/src/vmime/net/message.hpp369
-rw-r--r--vmime-master/src/vmime/net/messageSet.cpp430
-rw-r--r--vmime-master/src/vmime/net/messageSet.hpp358
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Command.cpp267
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Command.hpp123
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Connection.cpp737
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Connection.hpp132
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Folder.cpp822
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Folder.hpp179
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp88
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp75
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Message.cpp283
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Message.hpp124
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Response.cpp504
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Response.hpp194
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3SStore.cpp82
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3SStore.hpp74
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp142
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp91
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Store.cpp262
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Store.hpp120
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Utils.cpp135
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Utils.hpp92
-rw-r--r--vmime-master/src/vmime/net/pop3/pop3.hpp35
-rw-r--r--vmime-master/src/vmime/net/securedConnectionInfos.hpp55
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmail.hpp31
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp77
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp69
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp244
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp112
-rw-r--r--vmime-master/src/vmime/net/service.cpp170
-rw-r--r--vmime-master/src/vmime/net/service.hpp239
-rw-r--r--vmime-master/src/vmime/net/serviceFactory.cpp157
-rw-r--r--vmime-master/src/vmime/net/serviceFactory.hpp168
-rw-r--r--vmime-master/src/vmime/net/serviceInfos.cpp198
-rw-r--r--vmime-master/src/vmime/net/serviceInfos.hpp263
-rw-r--r--vmime-master/src/vmime/net/serviceRegistration.inl105
-rw-r--r--vmime-master/src/vmime/net/session.cpp188
-rw-r--r--vmime-master/src/vmime/net/session.hpp206
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp180
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp94
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommand.cpp258
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommand.hpp125
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp160
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp106
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPConnection.cpp714
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPConnection.hpp136
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp212
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp159
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPResponse.cpp366
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPResponse.hpp200
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp82
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp74
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp144
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp93
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPTransport.cpp502
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPTransport.hpp144
-rw-r--r--vmime-master/src/vmime/net/smtp/smtp.hpp33
-rw-r--r--vmime-master/src/vmime/net/socket.hpp223
-rw-r--r--vmime-master/src/vmime/net/store.cpp57
-rw-r--r--vmime-master/src/vmime/net/store.hpp115
-rw-r--r--vmime-master/src/vmime/net/timeoutHandler.hpp89
-rw-r--r--vmime-master/src/vmime/net/tls/TLSProperties.cpp44
-rw-r--r--vmime-master/src/vmime/net/tls/TLSProperties.hpp105
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp77
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp88
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSession.cpp48
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSession.hpp96
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSocket.cpp44
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSocket.hpp88
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp113
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp68
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp313
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp95
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp548
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp129
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp169
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp90
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp112
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp68
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp147
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp109
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp761
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp142
-rw-r--r--vmime-master/src/vmime/net/tracer.cpp74
-rw-r--r--vmime-master/src/vmime/net/tracer.hpp110
-rw-r--r--vmime-master/src/vmime/net/transport.cpp265
-rw-r--r--vmime-master/src/vmime/net/transport.hpp152
157 files changed, 36682 insertions, 0 deletions
diff --git a/vmime-master/src/vmime/net/builtinServices.inl b/vmime-master/src/vmime/net/builtinServices.inl
new file mode 100644
index 0000000..2f67d2e
--- /dev/null
+++ b/vmime-master/src/vmime/net/builtinServices.inl
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+// Include registration helpers
+#include "vmime/net/serviceRegistration.inl"
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_POP3
+ #include "vmime/net/pop3/POP3Store.hpp"
+ REGISTER_SERVICE(pop3::POP3Store, pop3, TYPE_STORE);
+
+ #if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/pop3/POP3SStore.hpp"
+ REGISTER_SERVICE(pop3::POP3SStore, pop3s, TYPE_STORE);
+ #endif // VMIME_HAVE_TLS_SUPPORT
+#endif
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_SMTP
+ #include "vmime/net/smtp/SMTPTransport.hpp"
+ REGISTER_SERVICE(smtp::SMTPTransport, smtp, TYPE_TRANSPORT);
+
+ #if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/smtp/SMTPSTransport.hpp"
+ REGISTER_SERVICE(smtp::SMTPSTransport, smtps, TYPE_TRANSPORT);
+ #endif // VMIME_HAVE_TLS_SUPPORT
+#endif
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_IMAP
+ #include "vmime/net/imap/IMAPStore.hpp"
+ REGISTER_SERVICE(imap::IMAPStore, imap, TYPE_STORE);
+
+ #if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/imap/IMAPSStore.hpp"
+ REGISTER_SERVICE(imap::IMAPSStore, imaps, TYPE_STORE);
+ #endif // VMIME_HAVE_TLS_SUPPORT
+#endif
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+ #include "vmime/net/maildir/maildirStore.hpp"
+ REGISTER_SERVICE(maildir::maildirStore, maildir, TYPE_STORE);
+#endif
+
+#if VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+ #include "vmime/net/sendmail/sendmailTransport.hpp"
+ REGISTER_SERVICE(sendmail::sendmailTransport, sendmail, TYPE_TRANSPORT);
+#endif
+
+
+#endif // VMIME_BUILDING_DOC
diff --git a/vmime-master/src/vmime/net/connectionInfos.hpp b/vmime-master/src/vmime/net/connectionInfos.hpp
new file mode 100644
index 0000000..0e519c7
--- /dev/null
+++ b/vmime-master/src/vmime/net/connectionInfos.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_CONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_CONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/object.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Information about the connection used by a service.
+ */
+class VMIME_EXPORT connectionInfos : public object {
+
+public:
+
+ /** Return the host to which the service is connected.
+ *
+ * @return server host name or address
+ */
+ virtual const string getHost() const = 0;
+
+ /** Return the port to which the service is connected.
+ *
+ * @return server port
+ */
+ virtual port_t getPort() const = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_CONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/defaultConnectionInfos.cpp b/vmime-master/src/vmime/net/defaultConnectionInfos.cpp
new file mode 100644
index 0000000..889f214
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultConnectionInfos.cpp
@@ -0,0 +1,60 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+defaultConnectionInfos::defaultConnectionInfos(const string& host, const port_t port)
+ : m_host(host), m_port(port) {
+
+}
+
+
+const string defaultConnectionInfos::getHost() const {
+
+ return m_host;
+}
+
+
+port_t defaultConnectionInfos::getPort() const {
+
+ return m_port;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/defaultConnectionInfos.hpp b/vmime-master/src/vmime/net/defaultConnectionInfos.hpp
new file mode 100644
index 0000000..f348859
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultConnectionInfos.hpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_DEFAULTCONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_DEFAULTCONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/connectionInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Information about the connection used by a service.
+ */
+class VMIME_EXPORT defaultConnectionInfos : public connectionInfos {
+
+public:
+
+ defaultConnectionInfos(const string& host, const port_t port);
+
+ const string getHost() const;
+ port_t getPort() const;
+
+private:
+
+ string m_host;
+ port_t m_port;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_DEFAULTCONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/defaultTimeoutHandler.cpp b/vmime-master/src/vmime/net/defaultTimeoutHandler.cpp
new file mode 100644
index 0000000..f5dcc7d
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultTimeoutHandler.cpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/defaultTimeoutHandler.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+defaultTimeoutHandler::defaultTimeoutHandler() {
+
+ m_startTime = time(NULL);
+}
+
+
+defaultTimeoutHandler::~defaultTimeoutHandler() {
+
+}
+
+
+bool defaultTimeoutHandler::isTimeOut() {
+
+ return time(NULL) - m_startTime >= 30;
+}
+
+
+void defaultTimeoutHandler::resetTimeOut() {
+
+ m_startTime = time(NULL);
+}
+
+
+bool defaultTimeoutHandler::handleTimeOut() {
+
+ return false;
+}
+
+
+
+
+shared_ptr <timeoutHandler> defaultTimeoutHandlerFactory::create() {
+
+ return make_shared <defaultTimeoutHandler>();
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/defaultTimeoutHandler.hpp b/vmime-master/src/vmime/net/defaultTimeoutHandler.hpp
new file mode 100644
index 0000000..545c655
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultTimeoutHandler.hpp
@@ -0,0 +1,80 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_DEFAULTTIMEOUTHANDLER_HPP_INCLUDED
+#define VMIME_NET_DEFAULTTIMEOUTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/timeoutHandler.hpp"
+
+#include <ctime>
+
+
+namespace vmime {
+namespace net {
+
+
+/** A default timeout handler for messaging services. The default action
+ * is to throw a exceptions::operation_timed_out exception when an
+ * operation is blocked for more than 30 seconds.
+ */
+class VMIME_EXPORT defaultTimeoutHandler : public timeoutHandler {
+
+public:
+
+ defaultTimeoutHandler();
+ ~defaultTimeoutHandler();
+
+ bool isTimeOut();
+ void resetTimeOut();
+ bool handleTimeOut();
+
+private:
+
+ time_t m_startTime;
+};
+
+
+/** A class that creates default timeout handlers.
+ */
+class defaultTimeoutHandlerFactory : public timeoutHandlerFactory {
+
+public:
+
+ shared_ptr <timeoutHandler> create();
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_DEFAULTTIMEOUTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/dsnAttributes.cpp b/vmime-master/src/vmime/net/dsnAttributes.cpp
new file mode 100644
index 0000000..dc949b9
--- /dev/null
+++ b/vmime-master/src/vmime/net/dsnAttributes.cpp
@@ -0,0 +1,71 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2020 Jan Osusky <jan@osusky.name>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/dsnAttributes.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+dsnAttributes::dsnAttributes(const string& dsnNotify, const string& dsnRet, const string& dsnEnvelopId)
+ : m_notifications(dsnNotify), m_returnFormat(dsnRet), m_envelopId(dsnEnvelopId) {
+
+}
+
+
+string dsnAttributes::getNotificationConditions() const {
+
+ return m_notifications;
+}
+
+
+string dsnAttributes::getReturnFormat() const {
+
+ return m_returnFormat;
+}
+
+
+string dsnAttributes::getEnvelopId() const {
+
+ return m_envelopId;
+}
+
+
+bool dsnAttributes::isEmpty() const {
+
+ return m_notifications.empty() && m_returnFormat.empty() && m_envelopId.empty();
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/dsnAttributes.hpp b/vmime-master/src/vmime/net/dsnAttributes.hpp
new file mode 100644
index 0000000..945da28
--- /dev/null
+++ b/vmime-master/src/vmime/net/dsnAttributes.hpp
@@ -0,0 +1,114 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2020 Jan Osusky <jan@osusky.name>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_DSNATTRIBUTES_HPP_INCLUDED
+#define VMIME_NET_DSNATTRIBUTES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds a set of attributes for Delivery Status Notifications (DSN).
+ */
+class VMIME_EXPORT dsnAttributes : public object {
+
+public:
+
+ /** Constructs an empty dsnAttributes object.
+ */
+ dsnAttributes() = default;
+
+ /** Constructs a new dsnAttributes object by copying an existing object.
+ *
+ * @param dsn object to copy
+ */
+ dsnAttributes(const dsnAttributes& dsn) = default;
+
+ /** Constructs a new dsnAttributes object by moving an existing object.
+ *
+ * @param dsn object (Rvalue reference) to move from.
+ */
+ dsnAttributes(dsnAttributes&& dsn) = default;
+
+ ~dsnAttributes() = default;
+
+ /** Constructs a new dsnAttributes object by specifying the attributes.
+ *
+ * @param dsnNotify comma separated list of notification conditions as specified in RFC 1891
+ * @param dsnRet content of DSN - full message or headers only ("FULL" or "HDRS")
+ * @param dsnEnvelopId envelop ID to be able to pair the DSN with original message (plain text not in "<" ">")
+ */
+ dsnAttributes(const string& dsnNotify, const string& dsnRet, const string& dsnEnvelopId);
+
+ /** Returns comma separated list of notification conditions as specified in RFC 1891
+ *
+ * @return comma separated list of notification conditions as specified in RFC 1891
+ */
+ string getNotificationConditions() const;
+
+ /** Returns requested format of the notification (RET parameter of the ESMTP MAIL command).
+ *
+ * @return requested format of the notification.
+ */
+ string getReturnFormat() const;
+
+ /** Returns envelop ID used to pair the DSN with the original message.
+ *
+ * @return envelop ID used to pair the DSN with the original message.
+ */
+ string getEnvelopId() const;
+
+ /** Returns whether the object is empty, and no attribute has been set.
+ *
+ * @return true if object is empty, or false otherwise
+ */
+ bool isEmpty() const;
+
+private:
+
+ string m_notifications;
+ string m_returnFormat;
+ string m_envelopId;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_DSNATTRIBUTES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/events.cpp b/vmime-master/src/vmime/net/events.cpp
new file mode 100644
index 0000000..8660812
--- /dev/null
+++ b/vmime-master/src/vmime/net/events.cpp
@@ -0,0 +1,180 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/events.hpp"
+#include "vmime/net/folder.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace events {
+
+
+//
+// event
+//
+
+event::event() {
+
+}
+
+
+event::~event() {
+
+}
+
+
+//
+// messageCountEvent
+//
+
+const char* messageCountEvent::EVENT_CLASS = "messageCountEvent";
+
+
+messageCountEvent::messageCountEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+)
+ : m_folder(folder),
+ m_type(type) {
+
+ m_nums.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), m_nums.begin());
+}
+
+
+shared_ptr <folder> messageCountEvent::getFolder() const { return (m_folder); }
+messageCountEvent::Types messageCountEvent::getType() const { return (m_type); }
+const std::vector <size_t>& messageCountEvent::getNumbers() const { return (m_nums); }
+
+
+void messageCountEvent::dispatch(messageCountListener* listener) {
+
+ if (m_type == TYPE_ADDED) {
+ listener->messagesAdded(dynamicCast <messageCountEvent>(shared_from_this()));
+ } else {
+ listener->messagesRemoved(dynamicCast <messageCountEvent>(shared_from_this()));
+ }
+}
+
+
+const char* messageCountEvent::getClass() const {
+
+ return EVENT_CLASS;
+}
+
+
+//
+// messageChangedEvent
+//
+
+const char* messageChangedEvent::EVENT_CLASS = "messageChangedEvent";
+
+
+messageChangedEvent::messageChangedEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+)
+ : m_folder(folder),
+ m_type(type) {
+
+ m_nums.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), m_nums.begin());
+}
+
+
+shared_ptr <folder> messageChangedEvent::getFolder() const { return (m_folder); }
+messageChangedEvent::Types messageChangedEvent::getType() const { return (m_type); }
+const std::vector <size_t>& messageChangedEvent::getNumbers() const { return (m_nums); }
+
+
+void messageChangedEvent::dispatch(messageChangedListener* listener) {
+
+ listener->messageChanged(dynamicCast <messageChangedEvent>(shared_from_this()));
+}
+
+
+const char* messageChangedEvent::getClass() const {
+
+ return EVENT_CLASS;
+}
+
+
+//
+// folderEvent
+//
+
+const char* folderEvent::EVENT_CLASS = "folderEvent";
+
+
+folderEvent::folderEvent(
+ const shared_ptr <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) {
+
+}
+
+
+shared_ptr <folder> folderEvent::getFolder() const { return (m_folder); }
+folderEvent::Types folderEvent::getType() const { return (m_type); }
+
+
+void folderEvent::dispatch(folderListener* listener) {
+
+ switch (m_type) {
+ case TYPE_CREATED: listener->folderCreated(dynamicCast <folderEvent>(shared_from_this())); break;
+ case TYPE_RENAMED: listener->folderRenamed(dynamicCast <folderEvent>(shared_from_this())); break;
+ case TYPE_DELETED: listener->folderDeleted(dynamicCast <folderEvent>(shared_from_this())); break;
+ }
+}
+
+
+const char* folderEvent::getClass() const {
+
+ return EVENT_CLASS;
+}
+
+
+} // events
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/events.hpp b/vmime-master/src/vmime/net/events.hpp
new file mode 100644
index 0000000..2ad64e7
--- /dev/null
+++ b/vmime-master/src/vmime/net/events.hpp
@@ -0,0 +1,276 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_EVENTS_HPP_INCLUDED
+#define VMIME_NET_EVENTS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/utility/path.hpp"
+
+
+namespace vmime {
+namespace net {
+
+class folder;
+
+namespace events {
+
+
+/** Event occurring on folders or messages.
+ */
+class VMIME_EXPORT event : public object, public enable_shared_from_this <event> {
+
+public:
+
+ event();
+ virtual ~event();
+
+ virtual const char* getClass() const = 0;
+};
+
+
+/** Event about the message count in a folder.
+ */
+class VMIME_EXPORT messageCountEvent : public event {
+
+public:
+
+ static const char* EVENT_CLASS;
+
+
+ enum Types {
+ TYPE_ADDED, /**< New messages have been added. */
+ TYPE_REMOVED /**< Messages have been expunged (renumbering). */
+ };
+
+
+ messageCountEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+ );
+
+ /** Return the folder in which messages have been added/removed.
+ *
+ * @return folder in which message count changed
+ */
+ shared_ptr <folder> getFolder() const;
+
+ /** Return the event type.
+ *
+ * @return event type (see messageCountEvent::Types)
+ */
+ Types getType() const;
+
+ /** Return the numbers of the messages that have been added/removed.
+ *
+ * @return a list of message numbers
+ */
+ const std::vector <size_t>& getNumbers() const;
+
+ /** Dispatch the event to the specified listener.
+ *
+ * @param listener listener to notify
+ */
+ void dispatch(class messageCountListener* listener);
+
+
+ const char* getClass() const;
+
+private:
+
+ shared_ptr <folder> m_folder;
+ const Types m_type;
+ std::vector <size_t> m_nums;
+};
+
+
+/** Listener for events about the message count in a folder.
+ */
+class VMIME_EXPORT messageCountListener {
+
+protected:
+
+ virtual ~messageCountListener() { }
+
+public:
+
+ virtual void messagesAdded(const shared_ptr <messageCountEvent>& event) = 0;
+ virtual void messagesRemoved(const shared_ptr <messageCountEvent>& event) = 0;
+};
+
+
+/** Event occuring on a message.
+ */
+class VMIME_EXPORT messageChangedEvent : public event {
+
+public:
+
+ static const char* EVENT_CLASS;
+
+
+ enum Types {
+ TYPE_FLAGS // flags changed
+ };
+
+
+ messageChangedEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+ );
+
+ /** Return the folder in which messages have changed.
+ *
+ * @return folder in which message count changed
+ */
+ shared_ptr <folder> getFolder() const;
+
+ /** Return the event type.
+ *
+ * @return event type (see messageChangedEvent::Types)
+ */
+ Types getType() const;
+
+ /** Return the numbers of the messages that have changed.
+ *
+ * @return a list of message numbers
+ */
+ const std::vector <size_t>& getNumbers() const;
+
+ /** Dispatch the event to the specified listener.
+ *
+ * @param listener listener to notify
+ */
+ void dispatch(class messageChangedListener* listener);
+
+
+ const char* getClass() const;
+
+private:
+
+ shared_ptr <folder> m_folder;
+ const Types m_type;
+ std::vector <size_t> m_nums;
+};
+
+
+/** Listener for events occuring on a message.
+ */
+class VMIME_EXPORT messageChangedListener {
+
+protected:
+
+ virtual ~messageChangedListener() { }
+
+public:
+
+ virtual void messageChanged(const shared_ptr <messageChangedEvent>& event) = 0;
+};
+
+
+/** Event occuring on a folder.
+ */
+class VMIME_EXPORT folderEvent : public event {
+
+public:
+
+ static const char* EVENT_CLASS;
+
+
+ enum Types {
+ TYPE_CREATED, /**< A folder was created. */
+ TYPE_DELETED, /**< A folder was deleted. */
+ TYPE_RENAMED /**< A folder was renamed. */
+ };
+
+
+ folderEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const utility::path& oldPath,
+ const utility::path& newPath
+ );
+
+ /** Return the folder on which the event occurred.
+ *
+ * @return folder on which the event occurred
+ */
+ shared_ptr <folder> getFolder() const;
+
+ /** Return the event type.
+ *
+ * @return event type (see folderEvent::Types)
+ */
+ Types getType() const;
+
+ /** Dispatch the event to the specified listener.
+ *
+ * @param listener listener to notify
+ */
+ void dispatch(class folderListener* listener);
+
+
+ const char* getClass() const;
+
+private:
+
+ shared_ptr <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 VMIME_EXPORT folderListener {
+
+protected:
+
+ virtual ~folderListener() { }
+
+public:
+
+ virtual void folderCreated(const shared_ptr <folderEvent>& event) = 0;
+ virtual void folderRenamed(const shared_ptr <folderEvent>& event) = 0;
+ virtual void folderDeleted(const shared_ptr <folderEvent>& event) = 0;
+};
+
+
+} // events
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_EVENTS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/fetchAttributes.cpp b/vmime-master/src/vmime/net/fetchAttributes.cpp
new file mode 100644
index 0000000..d9b54b8
--- /dev/null
+++ b/vmime-master/src/vmime/net/fetchAttributes.cpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/fetchAttributes.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+
+
+fetchAttributes::fetchAttributes()
+ : m_predefinedAttribs(0) {
+
+}
+
+
+fetchAttributes::fetchAttributes(const int attribs)
+ : m_predefinedAttribs(attribs) {
+
+}
+
+
+fetchAttributes::fetchAttributes(const fetchAttributes& attribs)
+ : object() {
+
+ m_predefinedAttribs = attribs.m_predefinedAttribs;
+ m_headers = attribs.m_headers;
+}
+
+
+void fetchAttributes::add(const int attribs) {
+
+ m_predefinedAttribs |= attribs;
+}
+
+
+void fetchAttributes::add(const string& header) {
+
+ m_headers.push_back(utility::stringUtils::toLower(header));
+}
+
+
+bool fetchAttributes::has(const int attribs) const {
+
+ return (m_predefinedAttribs & attribs) != 0;
+}
+
+
+bool fetchAttributes::has(const string& header) const {
+
+ return std::find(
+ m_headers.begin(), m_headers.end(),
+ utility::stringUtils::toLower(header)
+ ) != m_headers.end();
+}
+
+
+const std::vector <string> fetchAttributes::getHeaderFields() const {
+
+ return m_headers;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/fetchAttributes.hpp b/vmime-master/src/vmime/net/fetchAttributes.hpp
new file mode 100644
index 0000000..19d9262
--- /dev/null
+++ b/vmime-master/src/vmime/net/fetchAttributes.hpp
@@ -0,0 +1,140 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FETCHATTRIBUTES_HPP_INCLUDED
+#define VMIME_NET_FETCHATTRIBUTES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds a set of attributes to fetch for a message.
+ */
+class VMIME_EXPORT fetchAttributes : public object {
+
+public:
+
+ /** Predefined attributes that can be fetched.
+ */
+ enum PredefinedFetchAttributes {
+ ENVELOPE = (1 << 0), /**< Sender, recipients, date, subject. */
+ STRUCTURE = (1 << 1), /**< MIME structure (body parts). */
+ CONTENT_INFO = (1 << 2), /**< Top-level content type. */
+ FLAGS = (1 << 3), /**< Message flags. */
+ SIZE = (1 << 4), /**< Message size (exact or estimated). */
+ FULL_HEADER = (1 << 5), /**< Full RFC-[2]822 header. */
+ UID = (1 << 6), /**< Unique identifier (protocol specific). */
+ IMPORTANCE = (1 << 7), /**< Header fields suitable for use with misc::importanceHelper. */
+
+ CUSTOM = (1 << 16) /**< Reserved for future use. */
+ };
+
+ /** Constructs an empty fetchAttributes object.
+ */
+ fetchAttributes();
+
+ /** Constructs a new fetchAttributes object by specifying one or more
+ * predefined objects.
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ */
+ fetchAttributes(const int attribs);
+
+ /** Constructs a new fetchAttributes object by copying an existing object.
+ *
+ * @param attribs object to copy
+ */
+ fetchAttributes(const fetchAttributes& attribs);
+
+ /** Adds the specified predefined attribute to the set of attributes to fetch.
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ */
+ void add(const int attribs);
+
+ /** Adds the specified header field to the set of attributes to fetch.
+ * Fetching custom header fields is not supported by all protocols.
+ * At this time, only IMAP supports this.
+ *
+ * @param header name of header field (eg. "X-Mailer")
+ */
+ void add(const string& header);
+
+ /** Returns true if the set contains the specified attribute(s).
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ * @return true if the specified attributes are to be fetched
+ */
+ bool has(const int attribs) const;
+
+ /** Returns true if the set contains the specified header field.
+ *
+ * @param header name of header field (eg. "X-Mailer")
+ * @return true if the specified header fields are to be fetched
+ */
+ bool has(const string& header) const;
+
+ /** Returns true if the set contains the specified attribute(s).
+ *
+ * \deprecated Use the has() methods instead
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ * @return true if the specified attributes are to be fetched
+ */
+ VMIME_DEPRECATED inline bool operator&(const int attribs) const {
+ return has(attribs);
+ }
+
+ /** Returns a list of header fields to fetch.
+ *
+ * @return list of header names (eg. "X-Mailer")
+ */
+ const std::vector <string> getHeaderFields() const;
+
+private:
+
+ int m_predefinedAttribs;
+ std::vector <string> m_headers;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_FETCHATTRIBUTES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/folder.cpp b/vmime-master/src/vmime/net/folder.cpp
new file mode 100644
index 0000000..6e01b60
--- /dev/null
+++ b/vmime-master/src/vmime/net/folder.cpp
@@ -0,0 +1,134 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/folder.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+
+
+int folder::getType() {
+
+ return getAttributes().getType();
+}
+
+
+int folder::getFlags() {
+
+ return getAttributes().getFlags();
+}
+
+
+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 shared_ptr <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 shared_ptr <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 shared_ptr <events::folderEvent>& event) {
+
+ for (std::list <events::folderListener*>::iterator
+ it = m_folderListeners.begin() ; it != m_folderListeners.end() ; ++it) {
+
+ event->dispatch(*it);
+ }
+}
+
+
+void folder::notifyEvent(const shared_ptr <events::event>& event) {
+
+ if (event->getClass() == events::messageCountEvent::EVENT_CLASS) {
+ notifyMessageCount(dynamicCast <events::messageCountEvent>(event));
+ } else if (event->getClass() == events::messageChangedEvent::EVENT_CLASS) {
+ notifyMessageChanged(dynamicCast <events::messageChangedEvent>(event));
+ } else if (event->getClass() == events::folderEvent::EVENT_CLASS) {
+ notifyFolder(dynamicCast <events::folderEvent>(event));
+ }
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/folder.hpp b/vmime-master/src/vmime/net/folder.hpp
new file mode 100644
index 0000000..4d5cf6e
--- /dev/null
+++ b/vmime-master/src/vmime/net/folder.hpp
@@ -0,0 +1,440 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FOLDER_HPP_INCLUDED
+#define VMIME_NET_FOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/message.hpp"
+#include "vmime/net/message.hpp"
+#include "vmime/net/messageSet.hpp"
+#include "vmime/net/events.hpp"
+#include "vmime/net/folderStatus.hpp"
+#include "vmime/net/fetchAttributes.hpp"
+#include "vmime/net/folderAttributes.hpp"
+
+#include "vmime/utility/path.hpp"
+#include "vmime/utility/stream.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class store;
+
+
+/** Abstract representation of a folder in a message store.
+ */
+class VMIME_EXPORT folder : public object, public enable_shared_from_this <folder> {
+
+protected:
+
+ folder(const folder&) : object(), enable_shared_from_this <folder>() { }
+ folder() { }
+
+
+ enum PrivateConstants {
+ TYPE_UNDEFINED = 9999, /**< Used internally to indicate type has not
+ been initialized yet. */
+ FLAG_UNDEFINED = 9999 /**< Used internally to indicate flags have not
+ been initialized yet. */
+ };
+
+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). */
+ };
+
+
+ /** Return the type of this folder.
+ *
+ * \deprecated Use the getAttributes().getType() method instead
+ *
+ * @return folder type (see folderAttributes::Types enum)
+ */
+ int getType();
+
+ /** Return the flags of this folder.
+ *
+ * \deprecated Use the getAttributes().getFlags() method instead
+ *
+ * @return folder flags (see folderAttributes::Flags enum)
+ */
+ int getFlags();
+
+ /** Return the attributes of the folder.
+ *
+ * @return folder attributes (see folder::Flags)
+ */
+ virtual const folderAttributes getAttributes() = 0;
+
+ /** Return the mode in which the folder has been open.
+ *
+ * @return folder opening mode (see folder::Modes)
+ */
+ virtual 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.
+ * @throw exceptions::net_exception if an error occurs
+ * @throw exceptions::folder_already_open if the folder is already open
+ * in the same session
+ */
+ virtual void open(const int mode, bool failIfModeIsNotAvailable = false) = 0;
+
+ /** Close this folder.
+ *
+ * @param expunge if set to true, deleted messages are expunged
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void close(const bool expunge) = 0;
+
+ /** Create this folder.
+ *
+ * @param attribs attributes of the new folder
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void create(const folderAttributes& attribs) = 0;
+
+ /** Test whether this folder exists.
+ *
+ * @return true if the folder exists, false otherwise
+ */
+ virtual bool exists() = 0;
+
+ /** Delete this folder.
+ * The folder should be closed before attempting to delete it.
+ *
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void destroy() = 0;
+
+ /** Test whether this folder is open.
+ *
+ * @return true if the folder is open, false otherwise
+ */
+ virtual bool isOpen() const = 0;
+
+ /** Get a new reference to a message in this folder, given its number.
+ *
+ * @param num message sequence number
+ * @return a new object referencing the specified message
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual shared_ptr <message> getMessage(const size_t num) = 0;
+
+ /** Get new references to messages in this folder, given either their
+ * sequence numbers or UIDs.
+ *
+ * To retrieve messages by their number, use:
+ * \code{.cpp}
+ * // Get messages from sequence number 5 to sequence number 8 (including)
+ * folder->getMessage(vmime::net::messageSet::byNumber(5, 8));
+ *
+ * // Get all messages in the folder, starting from number 42
+ * folder->getMessage(vmime::net::messageSet::byNumber(42, -1));
+ * \endcode
+ * Or, to retrieve messages by their UID, use:
+ * \code{.cpp}
+ * // Get messages from UID 1000 to UID 1042 (including)
+ * folder->getMessage(vmime::net::messageSet::byUID(1000, 1042));
+ *
+ * // Get message with UID 1042
+ * folder->getMessage(vmime::net::messageSet::byUID(1042));
+ *
+ * // Get all messages in the folder, starting from UID 1000
+ * folder->getMessage(vmime::net::messageSet::byUID(1000, "*"));
+ * \endcode
+ *
+ * @param msgs index set of messages to retrieve
+ * @return new objects referencing the specified messages
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual std::vector <shared_ptr <message> > getMessages(const messageSet& msgs) = 0;
+
+ /** Return the number of messages in this folder.
+ *
+ * @return number of messages in the folder
+ */
+ virtual size_t 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
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual shared_ptr <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
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual std::vector <shared_ptr <folder> > getFolders(const bool recursive = false) = 0;
+
+ /** Rename (move) this folder to another location.
+ *
+ * @param newPath new path of the folder
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void rename(const folder::path& newPath) = 0;
+
+ /** Remove one or more messages from this folder.
+ *
+ * @param msgs index set of messages to delete
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void deleteMessages(const messageSet& msgs) = 0;
+
+ /** Change the flags for one or more messages in this folder.
+ *
+ * @param msgs index set of messages on which to set the flags
+ * @param flags set of flags (see message::Flags)
+ * @param mode indicate how to treat old and new flags (see message::FlagsModes)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void setMessageFlags(const messageSet& msgs, 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 (if -1, default flags are used)
+ * @param date date/time for the new message (if NULL, the current time is used)
+ * @param progress progress listener, or NULL if not used
+ * @return a message set containing the number or UID of the new message, or
+ * an empty set if the information could not be obtained (ie. the server does not
+ * support returning the number or UID of an added message)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* 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 (if -1, default flags are used)
+ * @param date date/time for the new message (if NULL, the current time is used)
+ * @param progress progress listener, or NULL if not used
+ * @return a message set containing the number or UID of the new message, or
+ * an empty set if the information could not be obtained (ie. the server does not
+ * support returning the number or UID of an added message)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ ) = 0;
+
+ /** Copy messages from this folder to another folder.
+ *
+ * @param dest destination folder path
+ * @param msgs index set of messages to copy
+ * @return a message set containing the number(s) or UID(s) of the copied message(s),
+ * or an empty set if the information could not be obtained (ie. the server does not
+ * support returning the number or UID of a copied message)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual messageSet copyMessages(
+ const folder::path& dest,
+ const messageSet& msgs
+ ) = 0;
+
+ /** Request folder status without opening it.
+ *
+ * \deprecated Use the new getStatus() method
+ *
+ * @param count will receive the number of messages in the folder
+ * @param unseen will receive the number of unseen messages in the folder
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void status(size_t& count, size_t& unseen) = 0;
+
+ /** Request folder status without opening it.
+ *
+ * @return current folder status
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual shared_ptr <folderStatus> getStatus() = 0;
+
+ /** Expunge deleted messages.
+ *
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void expunge() = 0;
+
+ /** Return a new folder object referencing the parent folder of this folder.
+ *
+ * @return parent folder object
+ */
+ virtual shared_ptr <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 shared_ptr <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 shared_ptr <store> getStore() = 0;
+
+ /** Fetch objects for the specified messages.
+ *
+ * @param msg list of message sequence numbers
+ * @param attribs set of attributes to fetch
+ * @param progress progress listener, or NULL if not used
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& attribs,
+ utility::progressListener* progress = NULL
+ ) = 0;
+
+ /** Fetch objects for the specified message.
+ *
+ * @param msg the message
+ * @param attribs set of attributes to fetch
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void fetchMessage(
+ const shared_ptr <message>& msg,
+ const fetchAttributes& attribs
+ ) = 0;
+
+ /** Get new references to messages in this folder, given either their
+ * sequence numbers or UIDs, and fetch objects for them at the same time.
+ *
+ * @param msgs index set of messages to retrieve
+ * @param attribs set of attributes to fetch
+ * @return new objects referencing the specified messages
+ * @throw exceptions::net_exception if an error occurs
+ * @see folder::getMessages()
+ * @see folder::fetchMessages()
+ */
+ virtual std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ ) = 0;
+
+ /** Return the list of fetchable objects supported by
+ * the underlying protocol (see folder::fetchAttributes).
+ *
+ * @return list of supported fetchable objects
+ */
+ virtual int getFetchCapabilities() const = 0;
+
+ /** Return the sequence numbers of messages whose UID equal or greater than
+ * the specified UID.
+ *
+ * @param uid the uid of the first message
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid) = 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 shared_ptr <events::messageChangedEvent>& event);
+ void notifyMessageCount(const shared_ptr <events::messageCountEvent>& event);
+ void notifyFolder(const shared_ptr <events::folderEvent>& event);
+ void notifyEvent(const shared_ptr <events::event>& event);
+
+private:
+
+ std::list <events::messageChangedListener*> m_messageChangedListeners;
+ std::list <events::messageCountListener*> m_messageCountListeners;
+ std::list <events::folderListener*> m_folderListeners;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_FOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/folderAttributes.cpp b/vmime-master/src/vmime/net/folderAttributes.cpp
new file mode 100644
index 0000000..107007c
--- /dev/null
+++ b/vmime-master/src/vmime/net/folderAttributes.cpp
@@ -0,0 +1,122 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/folderAttributes.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+
+
+folderAttributes::folderAttributes()
+ : m_type(TYPE_CONTAINS_FOLDERS | TYPE_CONTAINS_MESSAGES),
+ m_flags(0),
+ m_specialUse(SPECIALUSE_NONE) {
+
+}
+
+
+folderAttributes::folderAttributes(const folderAttributes& attribs)
+ : object(),
+ m_type(attribs.m_type),
+ m_flags(attribs.m_flags),
+ m_userFlags(attribs.m_userFlags),
+ m_specialUse(attribs.m_specialUse) {
+
+}
+
+
+int folderAttributes::getType() const {
+
+ return m_type;
+}
+
+
+void folderAttributes::setType(const int type) {
+
+ m_type = type;
+}
+
+
+int folderAttributes::getSpecialUse() const {
+
+ return m_specialUse;
+}
+
+
+void folderAttributes::setSpecialUse(const int use) {
+
+ m_specialUse = use;
+}
+
+
+int folderAttributes::getFlags() const {
+
+ return m_flags;
+}
+
+
+void folderAttributes::setFlags(const int flags) {
+
+ m_flags = flags;
+}
+
+
+bool folderAttributes::hasFlag(const int flag) {
+
+ return (m_flags & flag) != 0;
+}
+
+
+const std::vector <string> folderAttributes::getUserFlags() const {
+
+ return m_userFlags;
+}
+
+
+void folderAttributes::setUserFlags(const std::vector <string>& flags) {
+
+ m_userFlags = flags;
+}
+
+
+bool folderAttributes::hasUserFlag(const string& flag) {
+
+ return std::find(m_userFlags.begin(), m_userFlags.end(), flag) != m_userFlags.end();
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/folderAttributes.hpp b/vmime-master/src/vmime/net/folderAttributes.hpp
new file mode 100644
index 0000000..715b72a
--- /dev/null
+++ b/vmime-master/src/vmime/net/folderAttributes.hpp
@@ -0,0 +1,177 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED
+#define VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds a set of attributes for a folder.
+ */
+class VMIME_EXPORT folderAttributes : public object {
+
+public:
+
+ /** Folder types.
+ */
+ enum Types {
+ TYPE_CONTAINS_FOLDERS = (1 << 0), /**< Folder can contain folders. */
+ TYPE_CONTAINS_MESSAGES = (1 << 1) /**< Folder can contain messages. */
+ };
+
+ /** Folder flags.
+ */
+ enum Flags {
+ FLAG_HAS_CHILDREN = (1 << 0), /**< Folder contains subfolders. */
+ FLAG_NO_OPEN = (1 << 1) /**< Folder cannot be open. */
+ };
+
+ /** Folder special uses.
+ * Not all protocols support this. At the current time, only IMAP supports this,
+ * if the server has the SPECIAL-USE capability.
+ */
+ enum SpecialUses {
+ SPECIALUSE_NONE, /**< User folder, no special use (or unknown). */
+ SPECIALUSE_ALL, /**< Virtual folder containing all messages. */
+ SPECIALUSE_INBOX, /**< Inbox. */
+ SPECIALUSE_ARCHIVE, /**< Folder is used to archives messages (server-dependent). */
+ SPECIALUSE_DRAFTS, /**< Folder is used to hold draft messages - typically, messages
+ that are being composed but have not yet been sent. */
+ SPECIALUSE_FLAGGED, /**< Virtual folder containing all messages which are marked
+ in some way as "important" or "flagged". */
+ SPECIALUSE_JUNK, /**< Folder is used to hold junk mail. */
+ SPECIALUSE_SENT, /**< Folder is is used to hold copies of messages that have
+ been sent. */
+ SPECIALUSE_TRASH, /**< Folder is used to hold messages that have been deleted or
+ marked for deletion (may be a virtual folder). */
+ SPECIALUSE_IMPORTANT /**< Folder contains messages that are likely important to the
+ user. */
+ };
+
+
+ /** Construct a new folderAttributes object with the default set of attributes.
+ */
+ folderAttributes();
+
+ /** Construct a new folderAttributes object by copying an existing object.
+ *
+ * @param attribs object to copy
+ */
+ folderAttributes(const folderAttributes& attribs);
+
+ /** Return the type of the folder.
+ *
+ * @return combination of one ore more folder types (see folderAttributes::Types enum)
+ */
+ int getType() const;
+
+ /** Set the type of the folder.
+ *
+ * @param type combination of one ore more folder types (see folderAttributes::Types enum)
+ */
+ void setType(const int type);
+
+ /** Return the special use of the folder.
+ * Not all protocols support this. At the current time, only IMAP supports this,
+ * if the server has the SPECIAL-USE capability.
+ *
+ * @return a value which indicates a special use (see folderAttributes::SpecialUses enum)
+ */
+ int getSpecialUse() const;
+
+ /** Set the special use of the folder.
+ * Not all protocols support this. At the current time, only IMAP supports this,
+ * if the server has the SPECIAL-USE capability.
+ *
+ * @param use a value which indicates a special use (see folderAttributes::SpecialUses enum)
+ */
+ void setSpecialUse(const int use);
+
+ /** Return the standard (non-user) flags of the folder.
+ *
+ * @return combination of one ore more folder flags (see folderAttributes::Flags enum)
+ */
+ int getFlags() const;
+
+ /** Set the standard (non-user) flags of the folder.
+ *
+ * @param type combination of one ore more folder flags (see folderAttributes::Flags enum)
+ */
+ void setFlags(const int flags);
+
+ /** Return whether the specified folder flag(s) is/are set.
+ *
+ * @param flag combination of one ore more folder flags (see folderAttributes::Flags enum)
+ * @return true if the specified flags are all set, or false otherwise
+ */
+ bool hasFlag(const int flag);
+
+ /** Set the user-defined flags of the folder.
+ *
+ * @return a list of user-defined flags
+ */
+ const std::vector <string> getUserFlags() const;
+
+ /** Set the user-defined flags of the folder.
+ *
+ * @param flags a list of user-defined flags
+ */
+ void setUserFlags(const std::vector <string>& flags);
+
+ /** Return whether the specified user-defined flag is set.
+ *
+ * @return true if the specified flag is set, or false otherwise
+ */
+ bool hasUserFlag(const string& flag);
+
+private:
+
+ int m_type;
+ int m_flags;
+ std::vector <string> m_userFlags;
+ int m_specialUse;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/folderStatus.hpp b/vmime-master/src/vmime/net/folderStatus.hpp
new file mode 100644
index 0000000..fcc4afc
--- /dev/null
+++ b/vmime-master/src/vmime/net/folderStatus.hpp
@@ -0,0 +1,73 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds the status of a mail store folder.
+ */
+class VMIME_EXPORT folderStatus : public object {
+
+public:
+
+ /** Returns the total number of messages in the folder.
+ *
+ * @return number of messages
+ */
+ virtual size_t getMessageCount() const = 0;
+
+ /** Returns the number of unseen messages in the folder.
+ *
+ * @return number of unseen messages
+ */
+ virtual size_t getUnseenCount() const = 0;
+
+ /** Clones this object.
+ *
+ * @return a copy of this object
+ */
+ virtual shared_ptr <folderStatus> clone() const = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPCommand.cpp b/vmime-master/src/vmime/net/imap/IMAPCommand.cpp
new file mode 100644
index 0000000..8911ed0
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPCommand.cpp
@@ -0,0 +1,437 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPCommand.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+
+#include <sstream>
+
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPCommand::IMAPCommand(const string& text, const string& traceText)
+ : m_text(text),
+ m_traceText(traceText) {
+
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LOGIN(const string& username, const string& password) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LOGIN " << IMAPUtils::quoteString(username)
+ << " " << IMAPUtils::quoteString(password);
+
+ std::ostringstream trace;
+ trace.imbue(std::locale::classic());
+ trace << "LOGIN {username} {password}";
+
+ return createCommand(cmd.str(), trace.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::AUTHENTICATE(const string& mechName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTHENTICATE " << mechName;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::AUTHENTICATE(const string& mechName, const string& initialResponse) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTHENTICATE " << mechName << " " << initialResponse;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LIST(const string& refName, const string& mailboxName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LIST " << IMAPUtils::quoteString(refName)
+ << " " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::SELECT(
+ const bool readOnly,
+ const string& mailboxName,
+ const std::vector <string>& params
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (readOnly) {
+ cmd << "EXAMINE ";
+ } else {
+ cmd << "SELECT ";
+ }
+
+ cmd << IMAPUtils::quoteString(mailboxName);
+
+ if (!params.empty()) {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STATUS(
+ const string& mailboxName,
+ const std::vector <string>& attribs
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "STATUS " << IMAPUtils::quoteString(mailboxName);
+
+ cmd << " (";
+
+ for (size_t i = 0, n = attribs.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << attribs[i];
+ }
+
+ cmd << ")";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CREATE(
+ const string& mailboxName,
+ const std::vector <string>& params
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "CREATE " << IMAPUtils::quoteString(mailboxName);
+
+ if (!params.empty()) {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::DELETE(const string& mailboxName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "DELETE " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::RENAME(
+ const string& mailboxName,
+ const string& newMailboxName
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "RENAME " << IMAPUtils::quoteString(mailboxName)
+ << " " << IMAPUtils::quoteString(newMailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::FETCH(
+ const messageSet& msgs,
+ const std::vector <string>& params
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet()) {
+ cmd << "UID FETCH " << IMAPUtils::messageSetToSequenceSet(msgs);
+ } else {
+ cmd << "FETCH " << IMAPUtils::messageSetToSequenceSet(msgs);
+ }
+
+ if (params.size() == 1) {
+
+ cmd << " " << params[0];
+
+ } else {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STORE(
+ const messageSet& msgs,
+ const int mode,
+ const std::vector <string>& flags
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet()) {
+ cmd << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
+ } else {
+ cmd << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
+ }
+
+ if (mode == message::FLAG_MODE_ADD) {
+ cmd << " +FLAGS ";
+ } else if (mode == message::FLAG_MODE_REMOVE) {
+ cmd << " -FLAGS ";
+ } else { // if (mode == message::FLAG_MODE_SET)
+ cmd << " FLAGS ";
+ }
+
+ cmd << "(";
+
+ for (size_t i = 0, n = flags.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << flags[i];
+ }
+
+ cmd << ")";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::APPEND(
+ const string& mailboxName,
+ const std::vector <string>& flags,
+ vmime::datetime* date,
+ const size_t size
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "APPEND " << IMAPUtils::quoteString(mailboxName);
+
+ if (!flags.empty()) {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = flags.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << flags[i];
+ }
+
+ cmd << ")";
+ }
+
+ if (date != NULL) {
+ cmd << " " << IMAPUtils::dateTime(*date);
+ }
+
+ cmd << " {" << size << "}";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::COPY(
+ const messageSet& msgs,
+ const string& mailboxName
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet()) {
+ cmd << "UID COPY " << IMAPUtils::messageSetToSequenceSet(msgs);
+ } else {
+ cmd << "COPY " << IMAPUtils::messageSetToSequenceSet(msgs);
+ }
+
+ cmd << " " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::SEARCH(
+ const std::vector <string>& keys,
+ const vmime::charset* charset
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "SEARCH";
+
+ if (charset) {
+ cmd << " CHARSET " << charset->getName();
+ }
+
+ for (size_t i = 0, n = keys.size() ; i < n ; ++i) {
+ cmd << " " << keys[i];
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STARTTLS() {
+
+ return createCommand("STARTTLS");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CAPABILITY() {
+
+ return createCommand("CAPABILITY");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::NOOP() {
+
+ return createCommand("NOOP");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::EXPUNGE() {
+
+ return createCommand("EXPUNGE");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CLOSE() {
+
+ return createCommand("CLOSE");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LOGOUT() {
+
+ return createCommand("LOGOUT");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::createCommand(
+ const string& text,
+ const string& traceText
+) {
+
+ if (traceText.empty()) {
+ return shared_ptr <IMAPCommand>(new IMAPCommand(text, text));
+ } else {
+ return shared_ptr <IMAPCommand>(new IMAPCommand(text, traceText));
+ }
+}
+
+
+const string IMAPCommand::getText() const {
+
+ return m_text;
+}
+
+
+const string IMAPCommand::getTraceText() const {
+
+ return m_traceText;
+}
+
+
+void IMAPCommand::send(const shared_ptr <IMAPConnection>& conn) {
+
+ conn->sendCommand(dynamicCast <IMAPCommand>(shared_from_this()));
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
diff --git a/vmime-master/src/vmime/net/imap/IMAPCommand.hpp b/vmime-master/src/vmime/net/imap/IMAPCommand.hpp
new file mode 100644
index 0000000..4915a57
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPCommand.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPConnection;
+
+
+/** An IMAP command that will be sent to the server.
+ */
+class VMIME_EXPORT IMAPCommand : public object, public enable_shared_from_this <IMAPCommand> {
+
+public:
+
+ static shared_ptr <IMAPCommand> LOGIN(const string& username, const string& password);
+ static shared_ptr <IMAPCommand> AUTHENTICATE(const string& mechName);
+ static shared_ptr <IMAPCommand> AUTHENTICATE(const string& mechName, const string& initialResponse);
+ static shared_ptr <IMAPCommand> LIST(const string& refName, const string& mailboxName);
+ static shared_ptr <IMAPCommand> SELECT(const bool readOnly, const string& mailboxName, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> STATUS(const string& mailboxName, const std::vector <string>& attribs);
+ static shared_ptr <IMAPCommand> CREATE(const string& mailboxName, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> DELETE(const string& mailboxName);
+ static shared_ptr <IMAPCommand> RENAME(const string& mailboxName, const string& newMailboxName);
+ static shared_ptr <IMAPCommand> FETCH(const messageSet& msgs, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> STORE(const messageSet& msgs, const int mode, const std::vector <string>& flags);
+ static shared_ptr <IMAPCommand> APPEND(const string& mailboxName, const std::vector <string>& flags, vmime::datetime* date, const size_t size);
+ static shared_ptr <IMAPCommand> COPY(const messageSet& msgs, const string& mailboxName);
+ static shared_ptr <IMAPCommand> SEARCH(const std::vector <string>& keys, const vmime::charset* charset);
+ static shared_ptr <IMAPCommand> STARTTLS();
+ static shared_ptr <IMAPCommand> CAPABILITY();
+ static shared_ptr <IMAPCommand> NOOP();
+ static shared_ptr <IMAPCommand> EXPUNGE();
+ static shared_ptr <IMAPCommand> CLOSE();
+ static shared_ptr <IMAPCommand> LOGOUT();
+
+ /** Creates a new IMAP command with the specified text.
+ *
+ * @param text command text
+ * @param traceText trace text (if empty, command text is used)
+ * @return a new IMAPCommand object
+ */
+ static shared_ptr <IMAPCommand> createCommand(const string& text, const string& traceText = "");
+
+ /** Sends this command over the specified connection.
+ *
+ * @param conn connection onto which the command will be sent
+ */
+ virtual void send(const shared_ptr <IMAPConnection>& conn);
+
+ /** Returns the full text of the command, including command name
+ * and parameters (if any). This is the text that will be sent
+ * to the server.
+ *
+ * @return command text (eg. "LOGIN myusername mypassword")
+ */
+ virtual const string getText() const;
+
+ /** Returns the full text of the command, suitable for outputing
+ * to the tracer.
+ *
+ * @return trace text (eg. "LOGIN {username} {password}")
+ */
+ virtual const string getTraceText() const;
+
+protected:
+
+ IMAPCommand(const string& text, const string& traceText);
+ IMAPCommand(const IMAPCommand&);
+
+private:
+
+ string m_text;
+ string m_traceText;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPConnection.cpp b/vmime-master/src/vmime/net/imap/IMAPConnection.cpp
new file mode 100644
index 0000000..df3da1c
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPConnection.cpp
@@ -0,0 +1,886 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#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/net/imap/IMAPCommand.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/SASLContext.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/tls/TLSSession.hpp"
+ #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+#include <sstream>
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (m_store.lock()->getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const IMAPServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (m_store.lock()->getInfos().hasProperty(getSession(), \
+ dynamic_cast <const IMAPServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPConnection::IMAPConnection(
+ const shared_ptr <IMAPStore>& store,
+ const shared_ptr <security::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),
+ m_secured(false),
+ m_firstTag(true),
+ m_capabilitiesFetched(false),
+ m_noModSeq(false) {
+
+ static int connectionId = 0;
+
+ m_tag = make_shared <IMAPTag>();
+
+ if (store->getTracerFactory()) {
+ m_tracer = store->getTracerFactory()->create(store, ++connectionId);
+ }
+
+ m_parser = make_shared <IMAPParser>();
+ m_parser->setTracer(m_tracer);
+}
+
+
+IMAPConnection::~IMAPConnection() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ } else if (m_socket) {
+ internalDisconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+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);
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ // Create the time-out handler
+ if (store->getTimeoutHandlerFactory()) {
+ m_timeoutHandler = store->getTimeoutHandlerFactory()->create();
+ }
+
+ // Create and connect the socket
+ m_socket = store->getSocketFactory()->create(m_timeoutHandler);
+ m_socket->setTracer(m_tracer);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (store->isIMAPS()) { // dedicated port/IMAPS
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create
+ (store->getCertificateVerifier(),
+ store->getSession()->getTLSProperties());
+
+ shared_ptr <tls::TLSSocket> tlsSocket =
+ tlsSession->getSocket(m_socket);
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
+
+ } else
+#endif // VMIME_HAVE_TLS_SUPPORT
+ {
+ m_cntInfos = make_shared <defaultConnectionInfos>(address, port);
+ }
+
+ m_socket->connect(address, port);
+
+
+ m_parser->setSocket(m_socket);
+ m_parser->setTimeoutHandler(m_timeoutHandler);
+
+
+ setState(STATE_NON_AUTHENTICATED);
+
+
+ // Connection greeting
+ //
+ // eg: C: <connection to server>
+ // --- S: * OK mydomain.org IMAP4rev1 v12.256 server ready
+
+ scoped_ptr <IMAPParser::greeting> greet(m_parser->readGreeting());
+ bool needAuth = false;
+
+ if (greet->resp_cond_bye) {
+
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(greet->getErrorLog());
+
+ } else if (greet->resp_cond_auth->condition != IMAPParser::resp_cond_auth::PREAUTH) {
+
+ needAuth = true;
+ }
+
+ if (greet->resp_cond_auth->resp_text->resp_text_code &&
+ greet->resp_cond_auth->resp_text->resp_text_code->capability_data) {
+
+ processCapabilityResponseData(greet->resp_cond_auth->resp_text->resp_text_code->capability_data.get());
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+ // Setup secured connection, if requested
+ const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);
+ const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);
+
+ if (!store->isIMAPS() && tls) { // only if not IMAPS
+
+ try {
+
+ startTLS();
+
+ // Non-fatal error
+ } catch (exceptions::command_error&) {
+
+ if (tlsRequired) {
+ m_state = STATE_NONE;
+ throw;
+ } else {
+ // TLS is not required, so don't bother
+ }
+
+ // Fatal error
+ } catch (...) {
+
+ m_state = STATE_NONE;
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // Authentication
+ if (needAuth) {
+
+ try {
+
+ authenticate();
+
+ } catch (...) {
+
+ m_state = STATE_NONE;
+ throw;
+ }
+ }
+
+ // Get the hierarchy separator character
+ initHierarchySeparator();
+
+ // Switch to state "Authenticated"
+ setState(STATE_AUTHENTICATED);
+}
+
+
+void IMAPConnection::authenticate() {
+
+ getAuthenticator()->setService(m_store.lock());
+
+#if VMIME_HAVE_SASL_SUPPORT
+ // First, try SASL authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) {
+
+ try {
+
+ authenticateSASL();
+ return;
+
+ } catch (exceptions::authentication_error&) {
+
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK)) {
+
+ // Can't fallback on normal authentication
+ internalDisconnect();
+ throw;
+
+ } else {
+
+ // Ignore, will try normal authentication
+ }
+
+ } catch (exception&) {
+
+ internalDisconnect();
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Normal authentication
+ const string username = getAuthenticator()->getUsername();
+ const string password = getAuthenticator()->getPassword();
+
+ shared_ptr <IMAPConnection> conn = dynamicCast <IMAPConnection>(shared_from_this());
+ IMAPCommand::LOGIN(username, password)->send(conn);
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->isBad()) {
+
+ internalDisconnect();
+ throw exceptions::command_error("LOGIN", resp->getErrorLog());
+
+ } else if (resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(resp->getErrorLog());
+ }
+
+ // Server capabilities may change when logged in
+ if (!processCapabilityResponseData(resp.get())) {
+ invalidateCapabilities();
+ }
+}
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+void IMAPConnection::authenticateSASL() {
+
+ if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) {
+ throw exceptions::authentication_error("No SASL authenticator available.");
+ }
+
+ const std::vector <string> capa = getCapabilities();
+ std::vector <string> saslMechs;
+
+ for (unsigned int i = 0 ; i < capa.size() ; ++i) {
+
+ const string& x = capa[i];
+
+ if (x.length() > 5 &&
+ (x[0] == 'A' || x[0] == 'a') &&
+ (x[1] == 'U' || x[1] == 'u') &&
+ (x[2] == 'T' || x[2] == 't') &&
+ (x[3] == 'H' || x[3] == 'h') &&
+ x[4] == '=') {
+
+ saslMechs.push_back(string(x.begin() + 5, x.end()));
+ }
+ }
+
+ if (saslMechs.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList;
+
+ shared_ptr <security::sasl::SASLContext> saslContext =
+ security::sasl::SASLContext::create();
+
+ for (unsigned int i = 0 ; i < saslMechs.size() ; ++i) {
+
+ try {
+ mechList.push_back(saslContext->createMechanism(saslMechs[i]));
+ } catch (exceptions::no_such_mechanism&) {
+ // Ignore mechanism
+ }
+ }
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try to suggest a mechanism among all those supported
+ shared_ptr <security::sasl::SASLMechanism> suggestedMech =
+ saslContext->suggestMechanism(mechList);
+
+ if (!suggestedMech) {
+ throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
+ }
+
+ // Allow application to choose which mechanisms to use
+ mechList = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())->
+ getAcceptableMechanisms(mechList, suggestedMech);
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try each mechanism in the list in turn
+ for (unsigned int i = 0 ; i < mechList.size() ; ++i) {
+
+ shared_ptr <security::sasl::SASLMechanism> mech = mechList[i];
+
+ shared_ptr <security::sasl::SASLSession> saslSession =
+ saslContext->createSession("imap", getAuthenticator(), mech);
+
+ saslSession->init();
+
+ shared_ptr <IMAPCommand> authCmd;
+
+ if (saslSession->getMechanism()->hasInitialResponse()) {
+
+ byte_t* initialResp = 0;
+ size_t initialRespLen = 0;
+
+ saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
+
+ string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
+ delete [] initialResp;
+
+ if (encodedInitialResp.empty()) {
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName(), "=");
+ } else {
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName(), encodedInitialResp);
+ }
+
+ } else {
+
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName());
+ }
+
+ authCmd->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ for (bool cont = true ; cont ; ) {
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->response_done &&
+ resp->response_done->response_tagged &&
+ resp->response_done->response_tagged->resp_cond_state->
+ status == IMAPParser::resp_cond_state::OK) {
+
+ m_socket = saslSession->getSecuredSocket(m_socket);
+ return;
+
+ } else {
+
+ string response;
+ bool hasResponse = false;
+
+ for (auto &respData : resp->continue_req_or_response_data) {
+
+ if (respData->continue_req) {
+
+ response = respData->continue_req->resp_text->text;
+ hasResponse = true;
+ break;
+ }
+ }
+
+ if (!hasResponse) {
+ cont = false;
+ continue;
+ }
+
+ byte_t* challenge = 0;
+ size_t challengeLen = 0;
+
+ byte_t* resp = 0;
+ size_t respLen = 0;
+
+ try {
+
+ // Extract challenge
+ saslContext->decodeB64(response, &challenge, &challengeLen);
+
+ // Prepare response
+ saslSession->evaluateChallenge
+ (challenge, challengeLen, &resp, &respLen);
+
+ // Send response
+ const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n";
+ sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length());
+
+ if (m_tracer) {
+ m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange");
+ }
+
+ // Server capabilities may change when logged in
+ invalidateCapabilities();
+
+ } catch (exceptions::sasl_exception& e) {
+
+ if (challenge) {
+ delete [] challenge;
+ challenge = NULL;
+ }
+
+ if (resp) {
+ delete [] resp;
+ resp = NULL;
+ }
+
+ // Cancel SASL exchange
+ sendRaw(utility::stringUtils::bytesFromString("*\r\n"), 3);
+
+ if (m_tracer) {
+ m_tracer->traceSend("*");
+ }
+
+ } catch (...) {
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ throw;
+ }
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+ }
+ }
+ }
+
+ throw exceptions::authentication_error("Could not authenticate using SASL: all mechanisms failed.");
+}
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void IMAPConnection::startTLS() {
+
+ try {
+
+ IMAPCommand::STARTTLS()->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("STARTTLS", resp->getErrorLog(), "bad response");
+ }
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ m_store.lock()->getCertificateVerifier(),
+ m_store.lock()->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ tlsSocket->handshake();
+
+ m_socket = tlsSocket;
+ m_parser->setSocket(m_socket);
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(
+ m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket
+ );
+
+ // " Once TLS has been started, the client MUST discard cached
+ // information about server capabilities and SHOULD re-issue the
+ // CAPABILITY command. This is necessary to protect against
+ // man-in-the-middle attacks which alter the capabilities list prior
+ // to STARTTLS. " (RFC-2595)
+ invalidateCapabilities();
+
+ } catch (exceptions::command_error&) {
+
+ // Non-fatal error
+ throw;
+
+ } catch (exception&) {
+
+ // Fatal error
+ internalDisconnect();
+ throw;
+ }
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+const std::vector <string> IMAPConnection::getCapabilities() {
+
+ if (!m_capabilitiesFetched) {
+ fetchCapabilities();
+ }
+
+ return m_capabilities;
+}
+
+
+bool IMAPConnection::hasCapability(const string& capa) {
+
+ if (!m_capabilitiesFetched) {
+ fetchCapabilities();
+ }
+
+ const string normCapa = utility::stringUtils::toUpper(capa);
+
+ for (size_t i = 0, n = m_capabilities.size() ; i < n ; ++i) {
+
+ if (m_capabilities[i] == normCapa) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool IMAPConnection::hasCapability(const string& capa) const {
+
+ const string normCapa = utility::stringUtils::toUpper(capa);
+
+ for (size_t i = 0, n = m_capabilities.size() ; i < n ; ++i) {
+
+ if (m_capabilities[i] == normCapa)
+ return true;
+ }
+
+ return false;
+}
+
+
+void IMAPConnection::invalidateCapabilities() {
+
+ m_capabilities.clear();
+ m_capabilitiesFetched = false;
+}
+
+
+void IMAPConnection::fetchCapabilities() {
+
+ IMAPCommand::CAPABILITY()->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->response_done->response_tagged->
+ resp_cond_state->status == IMAPParser::resp_cond_state::OK) {
+
+ processCapabilityResponseData(resp.get());
+ }
+}
+
+
+bool IMAPConnection::processCapabilityResponseData(const IMAPParser::response* resp) {
+
+ for (auto &respData : resp->continue_req_or_response_data) {
+
+ if (respData->response_data == NULL) {
+ continue;
+ }
+
+ auto &capaData = respData->response_data->capability_data;
+
+ if (!capaData) {
+ continue;
+ }
+
+ processCapabilityResponseData(capaData.get());
+ return true;
+ }
+
+ return false;
+}
+
+
+void IMAPConnection::processCapabilityResponseData(const IMAPParser::capability_data* capaData) {
+
+ std::vector <string> res;
+
+ for (auto &cap : capaData->capabilities) {
+
+ if (cap->auth_type) {
+ res.push_back("AUTH=" + cap->auth_type->name);
+ } else {
+ res.push_back(utility::stringUtils::toUpper(cap->atom->value));
+ }
+ }
+
+ m_capabilities = res;
+ m_capabilitiesFetched = true;
+}
+
+
+shared_ptr <security::authenticator> IMAPConnection::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+bool IMAPConnection::isConnected() const {
+
+ return m_socket
+ && m_socket->isConnected()
+ && (m_state == STATE_AUTHENTICATED || m_state == STATE_SELECTED);
+}
+
+
+bool IMAPConnection::isSecuredConnection() const {
+
+ return m_secured;
+}
+
+
+shared_ptr <connectionInfos> IMAPConnection::getConnectionInfos() const {
+
+ return m_cntInfos;
+}
+
+
+void IMAPConnection::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ internalDisconnect();
+}
+
+
+void IMAPConnection::internalDisconnect() {
+
+ if (isConnected()) {
+
+ IMAPCommand::LOGOUT()->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ m_socket->disconnect();
+ m_socket = null;
+ }
+
+ m_timeoutHandler = null;
+
+ m_state = STATE_LOGOUT;
+
+ m_secured = false;
+ m_cntInfos = null;
+}
+
+
+void IMAPConnection::initHierarchySeparator() {
+
+ IMAPCommand::LIST("", "")->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ internalDisconnect();
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "bad response");
+ }
+
+ const auto& respDataList = resp->continue_req_or_response_data;
+
+ bool found = false;
+
+ for (unsigned int i = 0 ; !found && i < respDataList.size() ; ++i) {
+
+ if (!respDataList[i]->response_data) {
+ continue;
+ }
+
+ auto &mailboxData = respDataList[i]->response_data->mailbox_data;
+
+ if (!mailboxData || mailboxData->type != IMAPParser::mailbox_data::LIST) {
+ continue;
+ }
+
+ if (mailboxData->mailbox_list->quoted_char != '\0') {
+ m_hierarchySeparator = mailboxData->mailbox_list->quoted_char;
+ found = true;
+ }
+ }
+
+ if (!found) { // default
+ m_hierarchySeparator = '/';
+ }
+}
+
+
+void IMAPConnection::sendCommand(const shared_ptr <IMAPCommand>& cmd) {
+
+ if (!m_firstTag) {
+ ++(*m_tag);
+ }
+
+ m_socket->send(*m_tag);
+ m_socket->send(" ");
+ m_socket->send(cmd->getText());
+ m_socket->send("\r\n");
+
+ m_firstTag = false;
+
+ if (m_tracer) {
+
+ std::ostringstream oss;
+ oss << string(*m_tag) << " " << cmd->getText();
+
+ m_tracer->traceSend(oss.str());
+ }
+}
+
+
+void IMAPConnection::sendRaw(const byte_t* buffer, const size_t count) {
+
+ m_socket->sendRaw(buffer, count);
+}
+
+
+IMAPParser::response* IMAPConnection::readResponse(IMAPParser::literalHandler* lh) {
+
+ return m_parser->readResponse(*m_tag, lh);
+}
+
+
+IMAPConnection::ProtocolStates IMAPConnection::state() const {
+
+ return m_state;
+}
+
+
+void IMAPConnection::setState(const ProtocolStates state) {
+
+ m_state = state;
+}
+
+
+char IMAPConnection::hierarchySeparator() const {
+
+ return m_hierarchySeparator;
+}
+
+
+shared_ptr <const IMAPStore> IMAPConnection::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <IMAPStore> IMAPConnection::getStore() {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <session> IMAPConnection::getSession() {
+
+ return m_store.lock()->getSession();
+}
+
+
+shared_ptr <const socket> IMAPConnection::getSocket() const {
+
+ return m_socket;
+}
+
+
+void IMAPConnection::setSocket(const shared_ptr <socket>& sok) {
+
+ m_socket = sok;
+ m_parser->setSocket(sok);
+}
+
+
+shared_ptr <tracer> IMAPConnection::getTracer() {
+
+ return m_tracer;
+}
+
+
+shared_ptr <IMAPTag> IMAPConnection::getTag() {
+
+ return m_tag;
+}
+
+
+bool IMAPConnection::isMODSEQDisabled() const {
+
+ return m_noModSeq;
+}
+
+
+void IMAPConnection::disableMODSEQ() {
+
+ m_noModSeq = true;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPConnection.hpp b/vmime-master/src/vmime/net/imap/IMAPConnection.hpp
new file mode 100644
index 0000000..99750d4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPConnection.hpp
@@ -0,0 +1,172 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+#include "vmime/net/session.hpp"
+#include "vmime/net/connectionInfos.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPTag;
+class IMAPStore;
+class IMAPCommand;
+
+
+class VMIME_EXPORT IMAPConnection : public object, public enable_shared_from_this <IMAPConnection> {
+
+public:
+
+ IMAPConnection(const shared_ptr <IMAPStore>& store, const shared_ptr <security::authenticator>& auth);
+ ~IMAPConnection();
+
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+
+ enum ProtocolStates {
+ STATE_NONE,
+ STATE_NON_AUTHENTICATED,
+ STATE_AUTHENTICATED,
+ STATE_SELECTED,
+ STATE_LOGOUT
+ };
+
+ ProtocolStates state() const;
+ void setState(const ProtocolStates state);
+
+
+ char hierarchySeparator() const;
+
+
+ void sendCommand(const shared_ptr <IMAPCommand>& cmd);
+ void sendRaw(const byte_t* buffer, const size_t count);
+
+ IMAPParser::response* readResponse(IMAPParser::literalHandler* lh = NULL);
+
+
+ shared_ptr <const IMAPStore> getStore() const;
+ shared_ptr <IMAPStore> getStore();
+
+ shared_ptr <session> getSession();
+
+ void fetchCapabilities();
+ void invalidateCapabilities();
+ const std::vector <string> getCapabilities();
+ bool hasCapability(const string& capa);
+ bool hasCapability(const string& capa) const;
+
+ shared_ptr <security::authenticator> getAuthenticator();
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ shared_ptr <const socket> getSocket() const;
+ void setSocket(const shared_ptr <socket>& sok);
+
+ shared_ptr <tracer> getTracer();
+
+ shared_ptr <IMAPTag> getTag();
+
+ bool isMODSEQDisabled() const;
+ void disableMODSEQ();
+
+private:
+
+ void authenticate();
+#if VMIME_HAVE_SASL_SUPPORT
+ void authenticateSASL();
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ void startTLS();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ bool processCapabilityResponseData(const IMAPParser::response* resp);
+ void processCapabilityResponseData(const IMAPParser::capability_data* capaData);
+
+
+ weak_ptr <IMAPStore> m_store;
+
+ shared_ptr <security::authenticator> m_auth;
+
+ shared_ptr <socket> m_socket;
+
+ shared_ptr <IMAPParser> m_parser;
+
+ shared_ptr <IMAPTag> m_tag;
+
+ char m_hierarchySeparator;
+
+ ProtocolStates m_state;
+
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+
+ bool m_secured;
+ shared_ptr <connectionInfos> m_cntInfos;
+
+ bool m_firstTag;
+
+ std::vector <string> m_capabilities;
+ bool m_capabilitiesFetched;
+
+ bool m_noModSeq;
+
+ shared_ptr <tracer> m_tracer;
+
+
+ void internalDisconnect();
+
+ void initHierarchySeparator();
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolder.cpp b/vmime-master/src/vmime/net/imap/IMAPFolder.cpp
new file mode 100644
index 0000000..98bc05d
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolder.cpp
@@ -0,0 +1,1622 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPFolder.hpp"
+
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
+
+#include "vmime/message.hpp"
+
+#include "vmime/exception.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include <algorithm>
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPFolder::IMAPFolder(
+ const folder::path& path,
+ const shared_ptr <IMAPStore>& store,
+ const shared_ptr <folderAttributes>& attribs
+)
+ : m_store(store),
+ m_connection(store->connection()),
+ m_path(path),
+ m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()),
+ m_mode(-1),
+ m_open(false),
+ m_attribs(attribs) {
+
+ store->registerFolder(this);
+
+ m_status = make_shared <IMAPFolderStatus>();
+}
+
+
+IMAPFolder::~IMAPFolder() {
+
+ try {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (store) {
+
+ if (m_open) {
+ close(false);
+ }
+
+ store->unregisterFolder(this);
+
+ } else if (m_open) {
+
+ m_connection = null;
+ onClose();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+int IMAPFolder::getMode() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_mode;
+}
+
+
+const folderAttributes IMAPFolder::getAttributes() {
+
+ // Root folder
+ if (m_path.isEmpty()) {
+
+ folderAttributes attribs;
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
+ attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN | folderAttributes::FLAG_NO_OPEN);
+
+ return attribs;
+
+ } else {
+
+ if (!m_attribs) {
+ testExistAndGetType();
+ }
+
+ return *m_attribs;
+ }
+}
+
+
+const folder::path::component IMAPFolder::getName() const {
+
+ return m_name;
+}
+
+
+const folder::path IMAPFolder::getFullPath() const {
+
+ return m_path;
+}
+
+
+void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ // Ensure this folder is not already open in the same session
+ for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+ throw exceptions::folder_already_open();
+ }
+ }
+
+ // Open a connection for this folder
+ shared_ptr <IMAPConnection> connection =
+ make_shared <IMAPConnection>(store, store->getAuthenticator());
+
+ try {
+
+ connection->connect();
+
+ // Emit the "SELECT" command
+ //
+ // Example: C: A142 SELECT INBOX
+ // S: * 172 EXISTS
+ // S: * 1 RECENT
+ // S: * OK [UNSEEN 12] Message 12 is first unseen
+ // S: * OK [UIDVALIDITY 3857529045] UIDs valid
+ // S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+ // S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+ // S: A142 OK [READ-WRITE] SELECT completed
+
+ std::vector <string> selectParams;
+
+ if (m_connection->hasCapability("CONDSTORE")) {
+ selectParams.push_back("CONDSTORE");
+ }
+
+ IMAPCommand::SELECT(
+ mode == MODE_READ_ONLY,
+ IMAPUtils::pathToString(connection->hierarchySeparator(), getFullPath()),
+ selectParams
+ )->send(connection);
+
+ // Read the response
+ scoped_ptr <IMAPParser::response> resp(connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("SELECT", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ auto *responseData = (*it)->response_data.get();
+
+ if (!responseData) {
+ throw exceptions::command_error("SELECT", resp->getErrorLog(), "invalid response");
+ }
+
+ // OK Untagged responses: UNSEEN, PERMANENTFLAGS, UIDVALIDITY (optional)
+ if (responseData->resp_cond_state) {
+
+ auto *code = responseData->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (code) {
+
+ switch (code->type) {
+
+ case IMAPParser::resp_text_code::NOMODSEQ:
+
+ connection->disableMODSEQ();
+ break;
+
+ default:
+
+ break;
+ }
+ }
+
+ // Untagged responses: FLAGS, EXISTS, RECENT (required)
+ } else if (responseData->mailbox_data) {
+
+ switch (responseData->mailbox_data->type) {
+
+ default: break;
+
+ case IMAPParser::mailbox_data::FLAGS: {
+
+ if (!m_attribs) {
+ m_attribs = make_shared <folderAttributes>();
+ }
+
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ connection,
+ m_path,
+ *responseData->mailbox_data->mailbox_flag_list,
+ *m_attribs
+ );
+
+ break;
+ }
+ }
+ }
+ }
+
+ processStatusUpdate(resp.get());
+
+ // Check for access mode (read-only or read-write)
+ auto *respTextCode = resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (respTextCode) {
+
+ const int openMode =
+ (respTextCode->type == IMAPParser::resp_text_code::READ_WRITE)
+ ? MODE_READ_WRITE
+ : MODE_READ_ONLY;
+
+ if (failIfModeIsNotAvailable &&
+ mode == MODE_READ_WRITE && openMode == MODE_READ_ONLY) {
+
+ throw exceptions::operation_not_supported();
+ }
+ }
+
+ m_connection = connection;
+ m_open = true;
+ m_mode = mode;
+
+ } catch (std::exception&) {
+
+ throw;
+ }
+}
+
+
+void IMAPFolder::close(const bool expunge) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ shared_ptr <IMAPConnection> oldConnection = m_connection;
+
+ // Emit the "CLOSE" command to expunge messages marked
+ // as deleted (this is fastest than "EXPUNGE")
+ if (expunge) {
+
+ if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::operation_not_supported();
+ }
+
+ IMAPCommand::CLOSE()->send(oldConnection);
+ }
+
+ // Close this folder connection
+ oldConnection->disconnect();
+
+ // Now use default store connection
+ m_connection = m_store.lock()->connection();
+
+ m_open = false;
+ m_mode = -1;
+
+ m_status = make_shared <IMAPFolderStatus>();
+
+ onClose();
+}
+
+
+void IMAPFolder::onClose() {
+
+ for (std::vector <IMAPMessage*>::iterator it = m_messages.begin() ;
+ it != m_messages.end() ; ++it) {
+
+ (*it)->onFolderClosed();
+ }
+
+ m_messages.clear();
+}
+
+
+void IMAPFolder::create(const folderAttributes& attribs) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ } else if (exists()) {
+ throw exceptions::illegal_state("Folder already exists");
+ } else if (!store->isValidFolderName(m_name)) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Emit the "CREATE" command
+ //
+ // Example: C: A003 CREATE owatagusiam/
+ // S: A003 OK CREATE completed
+ // C: A004 CREATE owatagusiam/blurdybloop
+ // S: A004 OK CREATE completed
+
+ string mailbox = IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), getFullPath());
+
+ if (attribs.getType() & folderAttributes::TYPE_CONTAINS_FOLDERS) {
+ mailbox += m_connection->hierarchySeparator();
+ }
+
+ std::vector <string> createParams;
+
+ if (attribs.getSpecialUse() != folderAttributes::SPECIALUSE_NONE) {
+
+ if (!m_connection->hasCapability("CREATE-SPECIAL-USE")) {
+ throw exceptions::operation_not_supported();
+ }
+
+ // C: t2 CREATE MySpecial (USE (\Drafts \Sent))
+ std::ostringstream oss;
+ oss << "USE (";
+
+ switch (attribs.getSpecialUse()) {
+
+ case folderAttributes::SPECIALUSE_NONE: // should not happen
+ case folderAttributes::SPECIALUSE_ALL: oss << "\\All"; break;
+ case folderAttributes::SPECIALUSE_ARCHIVE: oss << "\\Archive"; break;
+ case folderAttributes::SPECIALUSE_DRAFTS: oss << "\\Drafts"; break;
+ case folderAttributes::SPECIALUSE_FLAGGED: oss << "\\Flagged"; break;
+ case folderAttributes::SPECIALUSE_JUNK: oss << "\\Junk"; break;
+ case folderAttributes::SPECIALUSE_SENT: oss << "\\Sent"; break;
+ case folderAttributes::SPECIALUSE_TRASH: oss << "\\Trash"; break;
+ case folderAttributes::SPECIALUSE_IMPORTANT: oss << "\\Important"; break;
+ }
+
+ oss << ")";
+
+ createParams.push_back(oss.str());
+ }
+
+ IMAPCommand::CREATE(mailbox, createParams)->send(m_connection);
+
+
+ scoped_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("CREATE", resp->getErrorLog(), "bad response");
+ }
+
+ // Notify folder created
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_CREATED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+void IMAPFolder::destroy() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ }
+
+ const string mailbox = IMAPUtils::pathToString(
+ m_connection->hierarchySeparator(), getFullPath()
+ );
+
+ IMAPCommand::DELETE(mailbox)->send(m_connection);
+
+
+ scoped_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("DELETE", resp->getErrorLog(), "bad response");
+ }
+
+ // Notify folder deleted
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_DELETED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+bool IMAPFolder::exists() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!isOpen() && !store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return testExistAndGetType() != -1;
+}
+
+
+int IMAPFolder::testExistAndGetType() {
+
+ // To test whether a folder exists, we simple list it using
+ // the "LIST" command, and there should be one unique mailbox
+ // with this name...
+ //
+ // Eg. Test whether '/foo/bar' exists
+ //
+ // C: a005 list "" foo/bar
+ // S: * LIST (\NoSelect) "/" foo/bar
+ // S: a005 OK LIST completed
+ //
+ // ==> OK, exists
+ //
+ // Test whether '/foo/bar/zap' exists
+ //
+ // C: a005 list "" foo/bar/zap
+ // S: a005 OK LIST completed
+ //
+ // ==> NO, does not exist
+
+ IMAPCommand::LIST(
+ "",
+ IMAPUtils::pathToString(
+ m_connection->hierarchySeparator(),
+ getFullPath()
+ )
+ )->send(m_connection);
+
+
+ scoped_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("LIST", resp->getErrorLog(), "bad response");
+ }
+
+ // Check whether the result mailbox list contains this folder
+ auto& respDataList = resp->continue_req_or_response_data;
+
+ folderAttributes attribs;
+ attribs.setType(-1);
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *mailboxData = (*it)->response_data->mailbox_data.get();
+
+ // We are only interested in responses of type "LIST"
+ if (mailboxData &&
+ mailboxData->type == IMAPParser::mailbox_data::LIST) {
+
+ // Get the folder type/flags at the same time
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ m_connection,
+ m_path,
+ *mailboxData->mailbox_list->mailbox_flag_list,
+ attribs
+ );
+ }
+ }
+
+ m_attribs = make_shared <folderAttributes>(attribs);
+
+ return m_attribs->getType();
+}
+
+
+bool IMAPFolder::isOpen() const {
+
+ return m_open;
+}
+
+
+shared_ptr <message> IMAPFolder::getMessage(const size_t num) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (num < 1 || num > m_status->getMessageCount()) {
+ throw exceptions::message_not_found();
+ }
+
+ return make_shared <IMAPMessage>(dynamicCast <IMAPFolder>(shared_from_this()), num);
+}
+
+
+std::vector <shared_ptr <message> > IMAPFolder::getMessages(const messageSet& msgs) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ std::vector <shared_ptr <message> > messages;
+
+ // Sequence number message set:
+ // C: . FETCH uuuu1,uuuu2,uuuu3 UID
+ // S: * nnnn1 FETCH (UID uuuu1)
+ // S: * nnnn2 FETCH (UID uuuu2)
+ // S: * nnnn3 FETCH (UID uuuu3)
+ // S: . OK FETCH completed
+
+ // UID message set:
+ // C: . UID FETCH uuuu1,uuuu2,uuuu3 UID
+ // S: * nnnn1 FETCH (UID uuuu1)
+ // S: * nnnn2 FETCH (UID uuuu2)
+ // S: * nnnn3 FETCH (UID uuuu3)
+ // S: . OK UID FETCH completed
+
+ std::vector <string> params;
+ params.push_back("UID");
+
+ IMAPCommand::FETCH(msgs, params)->send(m_connection);
+
+ // Get the response
+ scoped_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("UID FETCH ... UID", resp->getErrorLog(), "bad response");
+ }
+
+ // Process the response
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("UID FETCH ... UID", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *messageData = (*it)->response_data->message_data.get();
+
+ // We are only interested in responses of type "FETCH"
+ if (!messageData || messageData->type != IMAPParser::message_data::FETCH) {
+ continue;
+ }
+
+ // Find UID in message attributes
+ const size_t msgNum = messageData->number;
+ message::uid msgUID;
+
+ for (auto &att : messageData->msg_att->items) {
+
+ if (att->type == IMAPParser::msg_att_item::UID) {
+ msgUID = att->uniqueid->value;
+ break;
+ }
+ }
+
+ if (!msgUID.empty()) {
+ shared_ptr <IMAPFolder> thisFolder = dynamicCast <IMAPFolder>(shared_from_this());
+ messages.push_back(make_shared <IMAPMessage>(thisFolder, msgNum, msgUID));
+ }
+ }
+
+ return messages;
+}
+
+
+size_t IMAPFolder::getMessageCount() {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_status->getMessageCount();
+}
+
+
+vmime_uint32 IMAPFolder::getUIDValidity() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_status->getUIDValidity();
+}
+
+
+vmime_uint64 IMAPFolder::getHighestModSequence() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_status->getHighestModSeq();
+}
+
+
+shared_ptr <folder> IMAPFolder::getFolder(const folder::path::component& name) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return make_shared <IMAPFolder>(m_path / name, store, shared_ptr <folderAttributes>());
+}
+
+
+std::vector <shared_ptr <folder> > IMAPFolder::getFolders(const bool recursive) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!isOpen() && !store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ // Eg. List folders in '/foo/bar'
+ //
+ // C: a005 list "foo/bar" *
+ // S: * LIST (\NoSelect) "/" foo/bar
+ // S: * LIST (\NoInferiors) "/" foo/bar/zap
+ // S: a005 OK LIST completed
+
+ shared_ptr <IMAPCommand> cmd;
+
+ const string pathString = IMAPUtils::pathToString(
+ m_connection->hierarchySeparator(), getFullPath()
+ );
+
+ if (recursive) {
+
+ cmd = IMAPCommand::LIST(pathString, "*");
+
+ } else {
+
+ cmd = IMAPCommand::LIST(
+ pathString.empty()
+ ? ""
+ : (pathString + m_connection->hierarchySeparator()),
+ "%"
+ );
+ }
+
+ cmd->send(m_connection);
+
+
+ scoped_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("LIST", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ std::vector <shared_ptr <folder> > v;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *mailboxData = (*it)->response_data->mailbox_data.get();
+
+ if (!mailboxData || mailboxData->type != IMAPParser::mailbox_data::LIST) {
+ continue;
+ }
+
+ // Get folder path
+ auto &mailbox = mailboxData->mailbox_list->mailbox;
+
+ folder::path path = IMAPUtils::stringToPath(
+ mailboxData->mailbox_list->quoted_char, mailbox->name
+ );
+
+ if (recursive || m_path.isDirectParentOf(path)) {
+
+ // Append folder to list
+ shared_ptr <folderAttributes> attribs = make_shared <folderAttributes>();
+
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ m_connection,
+ path,
+ *mailboxData->mailbox_list->mailbox_flag_list,
+ *attribs
+ );
+
+ v.push_back(make_shared <IMAPFolder>(path, store, attribs));
+ }
+ }
+
+ return v;
+}
+
+
+void IMAPFolder::fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msg.empty()) {
+ return;
+ }
+
+ // Build message numbers list
+ std::vector <size_t> list;
+ list.reserve(msg.size());
+
+ std::map <size_t, shared_ptr <IMAPMessage> > numberToMsg;
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ; it != msg.end() ; ++it) {
+
+ list.push_back((*it)->getNumber());
+ numberToMsg[(*it)->getNumber()] = dynamicCast <IMAPMessage>(*it);
+ }
+
+ // Send the request
+ IMAPUtils::buildFetchCommand(
+ m_connection, messageSet::byNumber(list), options
+ )->send(m_connection);
+
+ // Get the response
+ scoped_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("FETCH", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ const size_t total = msg.size();
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ try {
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("FETCH", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *messageData = (*it)->response_data->message_data.get();
+
+ // We are only interested in responses of type "FETCH"
+ if (!messageData || messageData->type != IMAPParser::message_data::FETCH) {
+ continue;
+ }
+
+ // Process fetch response for this message
+ const size_t num = messageData->number;
+
+ std::map <size_t, shared_ptr <IMAPMessage> >::iterator msg = numberToMsg.find(num);
+
+ if (msg != numberToMsg.end()) {
+
+ (*msg).second->processFetchResponse(options, *messageData);
+
+ if (progress) {
+ progress->progress(++current, total);
+ }
+ }
+ }
+
+ } catch (...) {
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ throw;
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+void IMAPFolder::fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options) {
+
+ std::vector <shared_ptr <message> > msgs;
+ msgs.push_back(msg);
+
+ fetchMessages(msgs, options, /* progress */ NULL);
+}
+
+
+std::vector <shared_ptr <message> > IMAPFolder::getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ // Ensure we also get the UID for each message
+ fetchAttributes attribsWithUID(attribs);
+ attribsWithUID.add(fetchAttributes::UID);
+
+ // Send the request
+ IMAPUtils::buildFetchCommand(m_connection, msgs, attribsWithUID)->send(m_connection);
+
+ // Get the response
+ scoped_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("FETCH", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ std::vector <shared_ptr <message> > messages;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("FETCH", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *messageData = (*it)->response_data->message_data.get();
+
+ // We are only interested in responses of type "FETCH"
+ if (!messageData || messageData->type != IMAPParser::message_data::FETCH) {
+ continue;
+ }
+
+ // Get message number
+ const size_t msgNum = messageData->number;
+
+ // Get message UID
+ message::uid msgUID;
+
+ for (auto &att : messageData->msg_att->items) {
+
+ if (att->type == IMAPParser::msg_att_item::UID) {
+ msgUID = att->uniqueid->value;
+ break;
+ }
+ }
+
+ // Create a new message reference
+ shared_ptr <IMAPFolder> thisFolder = dynamicCast <IMAPFolder>(shared_from_this());
+ shared_ptr <IMAPMessage> msg = make_shared <IMAPMessage>(thisFolder, msgNum, msgUID);
+
+ messages.push_back(msg);
+
+ // Process fetch response for this message
+ msg->processFetchResponse(attribsWithUID, *messageData);
+ }
+
+ processStatusUpdate(resp.get());
+
+ return messages;
+}
+
+
+int IMAPFolder::getFetchCapabilities() const {
+
+ return fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO |
+ fetchAttributes::STRUCTURE | fetchAttributes::FLAGS |
+ fetchAttributes::SIZE | fetchAttributes::FULL_HEADER |
+ fetchAttributes::UID | fetchAttributes::IMPORTANCE;
+}
+
+
+shared_ptr <folder> IMAPFolder::getParent() {
+
+ if (m_path.isEmpty()) {
+
+ return null;
+
+ } else {
+
+ return make_shared <IMAPFolder>(
+ m_path.getParent(), m_store.lock(), shared_ptr <folderAttributes>()
+ );
+ }
+}
+
+
+shared_ptr <const store> IMAPFolder::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <store> IMAPFolder::getStore() {
+
+ return m_store.lock();
+}
+
+
+void IMAPFolder::registerMessage(IMAPMessage* msg) {
+
+ m_messages.push_back(msg);
+}
+
+
+void IMAPFolder::unregisterMessage(IMAPMessage* msg) {
+
+ std::vector <IMAPMessage*>::iterator it =
+ std::find(m_messages.begin(), m_messages.end(), msg);
+
+ if (it != m_messages.end()) {
+ m_messages.erase(it);
+ }
+}
+
+
+void IMAPFolder::onStoreDisconnected() {
+
+ m_store.reset();
+}
+
+
+void IMAPFolder::deleteMessages(const messageSet& msgs) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (msgs.isEmpty()) {
+ throw exceptions::invalid_argument();
+ }
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ // Send the request
+ IMAPCommand::STORE(
+ msgs, message::FLAG_MODE_ADD,
+ IMAPUtils::messageFlagList(message::FLAG_DELETED)
+ )->send(m_connection);
+
+ // Get the response
+ scoped_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("STORE", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+void IMAPFolder::setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode
+) {
+
+ const std::vector <string> flagList = IMAPUtils::messageFlagList(flags);
+
+ if ((mode == message::FLAG_MODE_SET) || !flagList.empty()) {
+
+ // Send the request
+ IMAPCommand::STORE(msgs, mode, flagList)->send(m_connection);
+
+ // Get the response
+ scoped_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("STORE", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+ }
+}
+
+
+messageSet IMAPFolder::addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags,
+ vmime::datetime* date,
+ utility::progressListener* progress
+) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ossAdapter);
+
+ const string& str = oss.str();
+ utility::inputStreamStringAdapter strAdapter(str);
+
+ return addMessage(strAdapter, str.length(), flags, date, progress);
+}
+
+
+messageSet IMAPFolder::addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags,
+ vmime::datetime* date,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ // Send the request
+ IMAPCommand::APPEND(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ IMAPUtils::messageFlagList(flags), date, size
+ )->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ bool ok = false;
+ auto &respList = resp->continue_req_or_response_data;
+
+ for (auto it = respList.begin() ; !ok && (it != respList.end()) ; ++it) {
+
+ if ((*it)->continue_req) {
+ ok = true;
+ }
+ }
+
+ if (!ok) {
+ throw exceptions::command_error("APPEND", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+
+ // Send message data
+ const size_t total = size;
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ const size_t blockSize = std::min(
+ is.getBlockSize(),
+ static_cast <size_t>(m_connection->getSocket()->getBlockSize())
+ );
+
+ std::vector <byte_t> vbuffer(blockSize);
+ byte_t* buffer = &vbuffer.front();
+
+ while (!is.eof()) {
+
+ // Read some data from the input stream
+ const size_t read = is.read(buffer, blockSize);
+ current += read;
+
+ // Put read data into socket output stream
+ m_connection->sendRaw(buffer, read);
+
+ // Notify progress
+ if (progress) {
+ progress->progress(current, total);
+ }
+ }
+
+ m_connection->sendRaw(utility::stringUtils::bytesFromString("\r\n"), 2);
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(current);
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> finalResp(m_connection->readResponse());
+
+ if (finalResp->isBad() || finalResp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("APPEND", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(finalResp.get());
+
+ auto *respTextCode =
+ finalResp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (respTextCode && respTextCode->type == IMAPParser::resp_text_code::APPENDUID) {
+ return IMAPUtils::buildMessageSet(*respTextCode->uid_set);
+ }
+
+ return messageSet::empty();
+}
+
+
+void IMAPFolder::expunge() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ // Send the request
+ IMAPCommand::EXPUNGE()->send(m_connection);
+
+ // Get the response
+ scoped_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("EXPUNGE", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+void IMAPFolder::rename(const folder::path& newPath) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (m_path.isEmpty() || newPath.isEmpty()) {
+ throw exceptions::illegal_operation("Cannot rename root folder");
+ } else if (m_path.getSize() == 1 && m_name.getBuffer() == "INBOX") {
+ throw exceptions::illegal_operation("Cannot rename 'INBOX' folder");
+ } else if (!store->isValidFolderName(newPath.getLastComponent())) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Send the request
+ IMAPCommand::RENAME(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), newPath)
+ )->send(m_connection);
+
+ // Get the response
+ scoped_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("RENAME", resp->getErrorLog(), "bad response");
+ }
+
+ // Notify folder renamed
+ folder::path oldPath(m_path);
+
+ m_path = newPath;
+ m_name = newPath.getLastComponent();
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath,
+ newPath
+ );
+
+ notifyFolder(event);
+
+ // Notify sub-folders
+ for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && oldPath.isParentOf((*it)->getFullPath())) {
+
+ folder::path oldPath((*it)->m_path);
+
+ (*it)->m_path.renameParent(oldPath, newPath);
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, (*it)->m_path
+ );
+
+ (*it)->notifyFolder(event);
+ }
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+messageSet IMAPFolder::copyMessages(const folder::path& dest, const messageSet& set) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ // Send the request
+ IMAPCommand::COPY(
+ set,
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), dest)
+ )->send(m_connection);
+
+ // Get the response
+ scoped_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("COPY", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+
+ auto *respTextCode =
+ resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (respTextCode && respTextCode->type == IMAPParser::resp_text_code::COPYUID) {
+ return IMAPUtils::buildMessageSet(*respTextCode->uid_set2);
+ }
+
+ return messageSet::empty();
+}
+
+
+void IMAPFolder::status(size_t& count, size_t& unseen) {
+
+ count = 0;
+ unseen = 0;
+
+ shared_ptr <folderStatus> status = getStatus();
+
+ count = status->getMessageCount();
+ unseen = status->getUnseenCount();
+}
+
+
+shared_ptr <folderStatus> IMAPFolder::getStatus() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ // Build the attributes list
+ std::vector <string> attribs;
+
+ attribs.push_back("MESSAGES");
+ attribs.push_back("UNSEEN");
+ attribs.push_back("UIDNEXT");
+ attribs.push_back("UIDVALIDITY");
+
+ if (m_connection->hasCapability("CONDSTORE")) {
+ attribs.push_back("HIGHESTMODSEQ");
+ }
+
+ // Send the request
+ IMAPCommand::STATUS(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ attribs
+ )->send(m_connection);
+
+ // Get the response
+ scoped_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("STATUS", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if ((*it)->response_data) {
+
+ auto &responseData = (*it)->response_data;
+
+ if (responseData->mailbox_data &&
+ responseData->mailbox_data->type == IMAPParser::mailbox_data::STATUS) {
+
+ shared_ptr <IMAPFolderStatus> status = make_shared <IMAPFolderStatus>();
+ status->updateFromResponse(*responseData->mailbox_data);
+
+ m_status->updateFromResponse(*responseData->mailbox_data);
+
+ return status;
+ }
+ }
+ }
+
+ throw exceptions::command_error("STATUS", resp->getErrorLog(), "invalid response");
+}
+
+
+void IMAPFolder::noop() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ IMAPCommand::NOOP()->send(m_connection);
+
+ scoped_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", resp->getErrorLog());
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+std::vector <size_t> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid) {
+
+ // Send the request
+ std::ostringstream uidSearchKey;
+ uidSearchKey.imbue(std::locale::classic());
+ uidSearchKey << "UID " << uid << ":*";
+
+ std::vector <string> searchKeys;
+ searchKeys.push_back(uidSearchKey.str());
+
+ IMAPCommand::SEARCH(searchKeys, /* charset */ NULL)->send(m_connection);
+
+ // Get the response
+ scoped_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("SEARCH", resp->getErrorLog(), "bad response");
+ }
+
+ auto& respDataList = resp->continue_req_or_response_data;
+
+ std::vector <size_t> seqNumbers;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("SEARCH", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *mailboxData = (*it)->response_data->mailbox_data.get();
+
+ // We are only interested in responses of type "SEARCH"
+ if (!mailboxData ||
+ mailboxData->type != IMAPParser::mailbox_data::SEARCH) {
+
+ continue;
+ }
+
+ for (auto &nzn : mailboxData->search_nz_number_list) {
+ seqNumbers.push_back(nzn->value);
+ }
+ }
+
+ processStatusUpdate(resp.get());
+
+ return seqNumbers;
+}
+
+
+void IMAPFolder::processStatusUpdate(const IMAPParser::response* resp) {
+
+ std::vector <shared_ptr <events::event> > events;
+
+ shared_ptr <IMAPFolderStatus> oldStatus = vmime::clone(m_status);
+ int expungedMessageCount = 0;
+
+ // Process tagged response
+ if (resp->response_done &&
+ resp->response_done->response_tagged &&
+ resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code) {
+
+ m_status->updateFromResponse(
+ *resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code
+ );
+ }
+
+ // Process untagged responses
+ for (auto it = resp->continue_req_or_response_data.begin() ;
+ it != resp->continue_req_or_response_data.end() ; ++it) {
+
+ if ((*it)->response_data &&
+ (*it)->response_data->resp_cond_state &&
+ (*it)->response_data->resp_cond_state->resp_text->resp_text_code) {
+
+ m_status->updateFromResponse(
+ *(*it)->response_data->resp_cond_state->resp_text->resp_text_code
+ );
+
+ } else if ((*it)->response_data &&
+ (*it)->response_data->mailbox_data) {
+
+ m_status->updateFromResponse(*(*it)->response_data->mailbox_data);
+
+ // Update folder attributes, if available
+ if ((*it)->response_data->mailbox_data->type == IMAPParser::mailbox_data::LIST) {
+
+ folderAttributes attribs;
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ m_connection,
+ m_path,
+ *(*it)->response_data->mailbox_data->mailbox_list->mailbox_flag_list,
+ attribs
+ );
+
+ m_attribs = make_shared <folderAttributes>(attribs);
+ }
+
+ } else if ((*it)->response_data && (*it)->response_data->message_data) {
+
+ auto* msgData = (*it)->response_data->message_data.get();
+ const size_t msgNumber = msgData->number;
+
+ if (msgData->type == IMAPParser::message_data::FETCH) {
+
+ // Message changed
+ for (std::vector <IMAPMessage*>::iterator mit =
+ m_messages.begin() ; mit != m_messages.end() ; ++mit) {
+
+ if ((*mit)->getNumber() == msgNumber) {
+ (*mit)->processFetchResponse(/* options */ 0, *msgData);
+ }
+ }
+
+ events.push_back(
+ make_shared <events::messageChangedEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageChangedEvent::TYPE_FLAGS,
+ std::vector <size_t>(1, msgNumber)
+ )
+ );
+
+ } else if (msgData->type == IMAPParser::message_data::EXPUNGE) {
+
+ // A message has been expunged, renumber messages
+ for (std::vector <IMAPMessage*>::iterator jt =
+ m_messages.begin() ; jt != m_messages.end() ; ++jt) {
+
+ if ((*jt)->getNumber() == msgNumber) {
+ (*jt)->setExpunged();
+ } else if ((*jt)->getNumber() > msgNumber) {
+ (*jt)->renumber((*jt)->getNumber() - 1);
+ }
+ }
+
+ events.push_back(
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_REMOVED,
+ std::vector <size_t>(1, msgNumber)
+ )
+ );
+
+ expungedMessageCount++;
+ }
+ }
+ }
+
+ // New messages arrived
+ if (m_status->getMessageCount() > oldStatus->getMessageCount() - expungedMessageCount) {
+
+ std::vector <size_t> newMessageNumbers;
+
+ for (size_t msgNumber = oldStatus->getMessageCount() - expungedMessageCount ;
+ msgNumber <= m_status->getMessageCount() ; ++msgNumber) {
+
+ newMessageNumbers.push_back(msgNumber);
+ }
+
+ events.push_back(
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ newMessageNumbers
+ )
+ );
+ }
+
+ // Dispatch notifications
+ for (std::vector <shared_ptr <events::event> >::iterator evit =
+ events.begin() ; evit != events.end() ; ++evit) {
+
+ notifyEvent(*evit);
+ }
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolder.hpp b/vmime-master/src/vmime/net/imap/IMAPFolder.hpp
new file mode 100644
index 0000000..3e6b04b
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolder.hpp
@@ -0,0 +1,230 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include <vector>
+#include <map>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPStore;
+class IMAPMessage;
+class IMAPConnection;
+class IMAPFolderStatus;
+
+
+/** IMAP folder implementation.
+ */
+class VMIME_EXPORT IMAPFolder : public folder {
+
+private:
+
+ friend class IMAPStore;
+ friend class IMAPMessage;
+
+ IMAPFolder(const IMAPFolder&);
+
+public:
+
+ IMAPFolder(
+ const folder::path& path,
+ const shared_ptr <IMAPStore>& store,
+ const shared_ptr <folderAttributes>& attribs
+ );
+
+ ~IMAPFolder();
+
+ int getMode() const;
+
+ const folderAttributes getAttributes();
+
+ 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 folderAttributes& attribs);
+
+ bool exists();
+
+ void destroy();
+
+ bool isOpen() const;
+
+ shared_ptr <message> getMessage(const size_t num);
+ std::vector <shared_ptr <message> > getMessages(const messageSet& msgs);
+
+ std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid);
+
+ size_t getMessageCount();
+
+ shared_ptr <folder> getFolder(const folder::path::component& name);
+ std::vector <shared_ptr <folder> > getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessages(const messageSet& msgs);
+
+ void setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode = message::FLAG_MODE_SET
+ );
+
+ messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet copyMessages(const folder::path& dest, const messageSet& msgs);
+
+ void status(size_t& count, size_t& unseen);
+ shared_ptr <folderStatus> getStatus();
+
+ void noop();
+
+ void expunge();
+
+ shared_ptr <folder> getParent();
+
+ shared_ptr <const store> getStore() const;
+ shared_ptr <store> getStore();
+
+
+ void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress = NULL
+ );
+
+ void fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options);
+
+ std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ );
+
+ int getFetchCapabilities() const;
+
+ /** Returns the UID validity of the folder for the current session.
+ * If the server is capable of persisting UIDs accross sessions,
+ * this value should never change for a folder. If the UID validity
+ * differs across sessions, then the UIDs obtained during a previous
+ * session may not correspond to the UIDs of the same messages in
+ * this session.
+ *
+ * @return UID validity of the folder
+ */
+ vmime_uint32 getUIDValidity() const;
+
+ /** Returns the highest modification sequence of this folder, ie the
+ * modification sequence of the last message that changed in this
+ * folder.
+ *
+ * @return modification sequence, or zero if not supported by
+ * the underlying protocol
+ */
+ vmime_uint64 getHighestModSequence() const;
+
+private:
+
+ void registerMessage(IMAPMessage* msg);
+ void unregisterMessage(IMAPMessage* msg);
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+ int testExistAndGetType();
+
+ void setMessageFlagsImpl(const string& set, const int flags, const int mode);
+
+ void copyMessagesImpl(const string& set, const folder::path& dest);
+
+
+ /** Process status updates ("unsolicited responses") contained in the
+ * specified response. Example:
+ *
+ * C: a006 NOOP
+ * S: * 930 EXISTS <-- this is a status update
+ * S: a006 OK Success
+ *
+ * @param resp parsed IMAP response
+ */
+ void processStatusUpdate(const IMAPParser::response* resp);
+
+
+ weak_ptr <IMAPStore> m_store;
+ shared_ptr <IMAPConnection> m_connection;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ shared_ptr <folderAttributes> m_attribs;
+
+ shared_ptr <IMAPFolderStatus> m_status;
+
+ std::vector <IMAPMessage*> m_messages;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp
new file mode 100644
index 0000000..55df337
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp
@@ -0,0 +1,292 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPFolderStatus::IMAPFolderStatus()
+ : m_count(0),
+ m_unseen(0),
+ m_recent(0),
+ m_uidValidity(0),
+ m_uidNext(0),
+ m_highestModSeq(0) {
+
+}
+
+
+IMAPFolderStatus::IMAPFolderStatus(const IMAPFolderStatus& other)
+ : folderStatus(),
+ m_count(other.m_count),
+ m_unseen(other.m_unseen),
+ m_recent(other.m_recent),
+ m_uidValidity(other.m_uidValidity),
+ m_uidNext(other.m_uidNext),
+ m_highestModSeq(other.m_highestModSeq) {
+
+}
+
+
+size_t IMAPFolderStatus::getMessageCount() const {
+
+ return m_count;
+}
+
+
+size_t IMAPFolderStatus::getUnseenCount() const {
+
+ return m_unseen;
+}
+
+
+size_t IMAPFolderStatus::getRecentCount() const {
+
+ return m_recent;
+}
+
+
+vmime_uint32 IMAPFolderStatus::getUIDValidity() const {
+
+ return m_uidValidity;
+}
+
+
+vmime_uint32 IMAPFolderStatus::getUIDNext() const {
+
+ return m_uidNext;
+}
+
+
+vmime_uint64 IMAPFolderStatus::getHighestModSeq() const {
+
+ return m_highestModSeq;
+}
+
+
+shared_ptr <folderStatus> IMAPFolderStatus::clone() const {
+
+ return make_shared <IMAPFolderStatus>(*this);
+}
+
+
+bool IMAPFolderStatus::updateFromResponse(const IMAPParser::mailbox_data& resp) {
+
+ bool changed = false;
+
+ if (resp.type == IMAPParser::mailbox_data::STATUS) {
+
+ for (auto &attval : resp.status_att_list->values) {
+
+ switch (attval->type) {
+
+ case IMAPParser::status_att_val::MESSAGES: {
+
+ const size_t count =
+ static_cast <size_t>(attval->value_as_number()->value);
+
+ if (m_count != count) {
+ m_count = count;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::UNSEEN: {
+
+ const size_t unseen =
+ static_cast <size_t>(attval->value_as_number()->value);
+
+ if (m_unseen != unseen) {
+ m_unseen = unseen;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::RECENT: {
+
+ const size_t recent =
+ static_cast <size_t>(attval->value_as_number()->value);
+
+ if (m_recent != recent) {
+ m_recent = recent;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::UIDNEXT: {
+
+ const vmime_uint32 uidNext =
+ static_cast <vmime_uint32>(attval->value_as_number()->value);
+
+ if (m_uidNext != uidNext) {
+ m_uidNext = uidNext;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::UIDVALIDITY: {
+
+ const vmime_uint32 uidValidity =
+ static_cast <vmime_uint32>(attval->value_as_number()->value);
+
+ if (m_uidValidity != uidValidity) {
+ m_uidValidity = uidValidity;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::HIGHESTMODSEQ: {
+
+ const vmime_uint64 highestModSeq =
+ static_cast <vmime_uint64>(attval->value_as_mod_sequence_value()->value);
+
+ if (m_highestModSeq != highestModSeq) {
+ m_highestModSeq = highestModSeq;
+ changed = true;
+ }
+
+ break;
+ }
+
+ }
+ }
+
+ } else if (resp.type == IMAPParser::mailbox_data::EXISTS) {
+
+ const size_t count =
+ static_cast <size_t>(resp.number->value);
+
+ if (m_count != count) {
+ m_count = count;
+ changed = true;
+ }
+
+ } else if (resp.type == IMAPParser::mailbox_data::RECENT) {
+
+ const size_t recent =
+ static_cast <size_t>(resp.number->value);
+
+ if (m_recent != recent) {
+ m_recent = recent;
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+
+bool IMAPFolderStatus::updateFromResponse(const IMAPParser::resp_text_code& resp) {
+
+ bool changed = false;
+
+ switch (resp.type) {
+
+ case IMAPParser::resp_text_code::UIDVALIDITY: {
+
+ const vmime_uint32 uidValidity =
+ static_cast <vmime_uint32>(resp.nz_number->value);
+
+ if (m_uidValidity != uidValidity) {
+ m_uidValidity = uidValidity;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::UIDNEXT: {
+
+ const vmime_uint32 uidNext =
+ static_cast <vmime_uint32>(resp.nz_number->value);
+
+ if (m_uidNext != uidNext) {
+ m_uidNext = uidNext;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::UNSEEN: {
+
+ const size_t unseen =
+ static_cast <size_t>(resp.nz_number->value);
+
+ if (m_unseen != unseen)
+ {
+ m_unseen = unseen;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::HIGHESTMODSEQ: {
+
+ const vmime_uint64 highestModSeq =
+ static_cast <vmime_uint64>(resp.mod_sequence_value->value);
+
+ if (m_highestModSeq != highestModSeq) {
+ m_highestModSeq = highestModSeq;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::NOMODSEQ: {
+
+ if (m_highestModSeq != 0) {
+ m_highestModSeq = 0;
+ changed = true;
+ }
+
+ break;
+ }
+ default:
+
+ break;
+ }
+
+ return changed;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp
new file mode 100644
index 0000000..b9a73ec
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/folderStatus.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+/** Holds the status of an IMAP folder.
+ */
+class VMIME_EXPORT IMAPFolderStatus : public folderStatus {
+
+public:
+
+ IMAPFolderStatus();
+ IMAPFolderStatus(const IMAPFolderStatus& other);
+
+ // Inherited from folderStatus
+ size_t getMessageCount() const;
+ size_t getUnseenCount() const;
+
+ shared_ptr <folderStatus> clone() const;
+
+ /** Returns the the number of messages with the Recent flag set.
+ *
+ * @return number of messages flagged Recent
+ */
+ size_t getRecentCount() const;
+
+ /** Returns the UID validity of the folder for the current session.
+ * If the server is capable of persisting UIDs accross sessions,
+ * this value should never change for a folder.
+ *
+ * @return UID validity of the folder
+ */
+ vmime_uint32 getUIDValidity() const;
+
+ /** Returns the UID value that will be assigned to a new message
+ * in the folder. If the server does not support the UIDPLUS
+ * extension, it will return 0.
+ *
+ * @return UID of the next message
+ */
+ vmime_uint32 getUIDNext() const;
+
+ /** Returns the highest modification sequence of all messages
+ * in the folder, or 0 if not available for this folder, or not
+ * supported by the server. The server must support the CONDSTORE
+ * extension for this to be available.
+ *
+ * @return highest modification sequence
+ */
+ vmime_uint64 getHighestModSeq() const;
+
+
+ /** Reads the folder status from the specified IMAP response.
+ *
+ * @param resp parsed IMAP response
+ * @return true if the status changed, or false otherwise
+ */
+ bool updateFromResponse(const IMAPParser::mailbox_data& resp);
+
+ /** Reads the folder status from the specified IMAP response.
+ *
+ * @param resp parsed IMAP response
+ * @return true if the status changed, or false otherwise
+ */
+ bool updateFromResponse(const IMAPParser::resp_text_code& resp);
+
+private:
+
+ size_t m_count;
+ size_t m_unseen;
+ size_t m_recent;
+ vmime_uint32 m_uidValidity;
+ vmime_uint32 m_uidNext;
+ vmime_uint64 m_highestModSeq;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessage.cpp b/vmime-master/src/vmime/net/imap/IMAPMessage.cpp
new file mode 100644
index 0000000..f74a4a4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessage.cpp
@@ -0,0 +1,760 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPParser.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPMessageStructure.hpp"
+#include "vmime/net/imap/IMAPMessagePart.hpp"
+#include "vmime/net/imap/IMAPMessagePartContentHandler.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include <sstream>
+#include <iterator>
+#include <typeinfo>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+//
+// IMAPMessage_literalHandler
+//
+
+class IMAPMessage_literalHandler : public IMAPParser::literalHandler {
+
+public:
+
+ IMAPMessage_literalHandler(utility::outputStream& os, utility::progressListener* progress) {
+
+ m_target = shared_ptr <target>(new targetStream(progress, os));
+ }
+
+ shared_ptr <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 m_target;
+ }
+ }
+
+ return shared_ptr <target>();
+ }
+
+ shared_ptr <target> getTarget() {
+
+ return m_target;
+ }
+
+private:
+
+ shared_ptr <target> m_target;
+};
+
+#endif // VMIME_BUILDING_DOC
+
+
+
+//
+// IMAPMessage
+//
+
+
+IMAPMessage::IMAPMessage(
+ const shared_ptr <IMAPFolder>& folder,
+ const size_t num
+)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1U),
+ m_flags(FLAG_UNDEFINED),
+ m_expunged(false),
+ m_modseq(0),
+ m_structure(null) {
+
+ folder->registerMessage(this);
+}
+
+
+IMAPMessage::IMAPMessage(
+ const shared_ptr <IMAPFolder>& folder,
+ const size_t num,
+ const uid& uid
+)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1),
+ m_flags(FLAG_UNDEFINED),
+ m_expunged(false),
+ m_uid(uid),
+ m_modseq(0),
+ m_structure(null) {
+
+ folder->registerMessage(this);
+}
+
+
+IMAPMessage::~IMAPMessage() {
+
+ try {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ if (folder) {
+ folder->unregisterMessage(this);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void IMAPMessage::onFolderClosed() {
+
+ m_folder.reset();
+}
+
+
+size_t IMAPMessage::getNumber() const {
+
+ return m_num;
+}
+
+
+const message::uid IMAPMessage::getUID() const {
+
+ return m_uid;
+}
+
+
+vmime_uint64 IMAPMessage::getModSequence() const {
+
+ return m_modseq;
+}
+
+
+size_t IMAPMessage::getSize() const {
+
+ if (m_size == -1U) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_size;
+}
+
+
+bool IMAPMessage::isExpunged() const {
+
+ return m_expunged;
+}
+
+
+int IMAPMessage::getFlags() const {
+
+ if (m_flags == FLAG_UNDEFINED) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_flags;
+}
+
+
+shared_ptr <const messageStructure> IMAPMessage::getStructure() const {
+
+ if (m_structure == NULL) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <messageStructure> IMAPMessage::getStructure() {
+
+ if (m_structure == NULL) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <const header> IMAPMessage::getHeader() const {
+
+ if (m_header == NULL) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_header;
+}
+
+
+void IMAPMessage::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ shared_ptr <const IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ extractImpl(
+ null, os, progress, start, length,
+ EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)
+ );
+}
+
+
+void IMAPMessage::extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ shared_ptr <const IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ extractImpl(
+ p, os, progress, start, length,
+ EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)
+ );
+}
+
+
+void IMAPMessage::fetchPartHeader(const shared_ptr <messagePart>& p) {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ extractImpl(p, ossAdapter, NULL, 0, -1, EXTRACT_HEADER | EXTRACT_PEEK);
+
+ dynamicCast <IMAPMessagePart>(p)->getOrCreateHeader().parse(oss.str());
+}
+
+
+void IMAPMessage::fetchPartHeaderForStructure(const shared_ptr <messageStructure>& str) {
+
+ for (size_t i = 0, n = str->getPartCount() ; i < n ; ++i) {
+
+ shared_ptr <messagePart> part = str->getPartAt(i);
+
+ // Fetch header of current part
+ fetchPartHeader(part);
+
+ // Fetch header of sub-parts
+ fetchPartHeaderForStructure(part->getStructure());
+ }
+}
+
+
+size_t IMAPMessage::extractImpl(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const int extractFlags
+) const {
+
+ shared_ptr <const IMAPFolder> folder = m_folder.lock();
+
+ IMAPMessage_literalHandler literalHandler(os, progress);
+
+ if (length == 0) {
+ return 0;
+ }
+
+ // Construct section identifier
+ std::ostringstream section;
+ section.imbue(std::locale::classic());
+
+ if (p != NULL) {
+
+ shared_ptr <const IMAPMessagePart> currentPart = dynamicCast <const IMAPMessagePart>(p);
+ std::vector <size_t> 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 <size_t>::reverse_iterator it = numbers.rbegin() ; it != numbers.rend() ; ++it) {
+ if (it != numbers.rbegin()) section << ".";
+ section << (*it + 1);
+ }
+ }
+
+ // Build the body descriptor for FETCH
+ /*
+ BODY[] header + body
+ BODY.PEEK[] header + body (peek)
+ BODY[HEADER] header
+ BODY.PEEK[HEADER] header (peek)
+ BODY[TEXT] body
+ BODY.PEEK[TEXT] body (peek)
+ */
+ std::ostringstream bodyDesc;
+ bodyDesc.imbue(std::locale::classic());
+
+ bodyDesc << "BODY";
+
+ if (extractFlags & EXTRACT_PEEK) {
+ bodyDesc << ".PEEK";
+ }
+
+ bodyDesc << "[";
+
+ if (section.str().empty()) {
+
+ // header + body
+ if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) {
+ bodyDesc << "";
+ // body only
+ } else if (extractFlags & EXTRACT_BODY) {
+ bodyDesc << "TEXT";
+ // header only
+ } else if (extractFlags & EXTRACT_HEADER) {
+ bodyDesc << "HEADER";
+ }
+
+ } else {
+
+ bodyDesc << section.str();
+
+ // header + body
+ if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) {
+
+ // First, extract header
+ std::ostringstream header;
+ utility::outputStreamAdapter headerStream(header);
+
+ const size_t headerLength = extractImpl(
+ p, headerStream, /* progress */ NULL,
+ /* start */ 0, /* length */ -1, extractFlags & ~EXTRACT_BODY
+ );
+
+ size_t s = start;
+ size_t l = length;
+
+ if (s < headerLength) {
+
+ if (l == static_cast <size_t>(-1)) {
+
+ os.write(header.str().data() + s, headerLength - s);
+
+ } else {
+
+ size_t headerCopyLength = l;
+
+ if (start + headerCopyLength > headerLength) {
+ headerCopyLength = headerLength - start;
+ }
+
+ os.write(header.str().data() + s, headerCopyLength);
+
+ l -= headerCopyLength;
+ }
+
+ s = 0;
+
+ } else {
+
+ s -= headerLength;
+ }
+
+ // Then, extract body
+ return extractImpl(p, os, progress, s, l, extractFlags & ~EXTRACT_HEADER);
+
+ // header only
+ } else if (extractFlags & EXTRACT_HEADER) {
+
+ bodyDesc << ".MIME"; // "MIME" not "HEADER" for parts
+ }
+ }
+
+ bodyDesc << "]";
+
+ if (start != 0 || length != static_cast <size_t>(-1)) {
+
+ if (length == static_cast <size_t>(-1)) {
+ bodyDesc << "<" << start << "." << static_cast <unsigned int>(-1) << ">";
+ } else {
+ bodyDesc << "<" << start << "." << length << ">";
+ }
+ }
+
+ std::vector <std::string> fetchParams;
+ fetchParams.push_back(bodyDesc.str());
+
+ // Send the request
+ IMAPCommand::FETCH(
+ m_uid.empty() ? messageSet::byNumber(m_num) : messageSet::byUID(m_uid),
+ fetchParams
+ )->send(folder->m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(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", resp->getErrorLog(), "bad response");
+ }
+
+
+ if (extractFlags & EXTRACT_BODY) {
+ // TODO: update the flags (eg. flag "\Seen" may have been set)
+ }
+
+ return literalHandler.getTarget()->getBytesWritten();
+}
+
+
+int IMAPMessage::processFetchResponse(
+ const fetchAttributes& options,
+ const IMAPParser::message_data& msgData
+) {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ // Get message attributes
+ int changes = 0;
+
+ for (auto &att : msgData.msg_att->items) {
+
+ switch (att->type) {
+
+ case IMAPParser::msg_att_item::FLAGS: {
+
+ int flags = IMAPUtils::messageFlagsFromFlags(*att->flag_list);
+
+ if (m_flags != flags) {
+ m_flags = flags;
+ changes |= events::messageChangedEvent::TYPE_FLAGS;
+ }
+
+ break;
+ }
+ case IMAPParser::msg_att_item::UID: {
+
+ m_uid = att->uniqueid->value;
+ break;
+ }
+ case IMAPParser::msg_att_item::MODSEQ: {
+
+ m_modseq = att->mod_sequence_value->value;
+ break;
+ }
+ case IMAPParser::msg_att_item::ENVELOPE: {
+
+ if (!options.has(fetchAttributes::FULL_HEADER)) {
+
+ auto* env = att->envelope.get();
+ shared_ptr <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;
+ IMAPUtils::convertAddressList(*(env->env_from), from);
+
+ if (!from.isEmpty()) {
+ hdr->From()->setValue(*(from.getMailboxAt(0)));
+ }
+
+ // To
+ mailboxList to;
+ IMAPUtils::convertAddressList(*(env->env_to), to);
+
+ hdr->To()->setValue(to.toAddressList());
+
+ // Sender
+ mailboxList sender;
+ IMAPUtils::convertAddressList(*(env->env_sender), sender);
+
+ if (!sender.isEmpty()) {
+ hdr->Sender()->setValue(*(sender.getMailboxAt(0)));
+ }
+
+ // Reply-to
+ mailboxList replyTo;
+ IMAPUtils::convertAddressList(*(env->env_reply_to), replyTo);
+
+ if (!replyTo.isEmpty()) {
+ hdr->ReplyTo()->setValue(*(replyTo.getMailboxAt(0)));
+ }
+
+ // Cc
+ mailboxList cc;
+ IMAPUtils::convertAddressList(*(env->env_cc), cc);
+
+ if (!cc.isEmpty()) {
+ hdr->Cc()->setValue(cc.toAddressList());
+ }
+
+ // Bcc
+ mailboxList bcc;
+ IMAPUtils::convertAddressList(*(env->env_bcc), bcc);
+
+ if (!bcc.isEmpty()) {
+ hdr->Bcc()->setValue(bcc.toAddressList());
+ }
+ }
+
+ break;
+ }
+ case IMAPParser::msg_att_item::BODY_STRUCTURE: {
+
+ m_structure = make_shared <IMAPMessageStructure>(att->body.get());
+ break;
+ }
+ case IMAPParser::msg_att_item::RFC822_HEADER: {
+
+ getOrCreateHeader()->parse(att->nstring->value);
+ break;
+ }
+ case IMAPParser::msg_att_item::RFC822_SIZE: {
+
+ m_size = static_cast <size_t>(att->number->value);
+ break;
+ }
+ case IMAPParser::msg_att_item::BODY_SECTION: {
+
+ if (!options.has(fetchAttributes::FULL_HEADER)) {
+
+ if (att->section->section_text1 &&
+ att->section->section_text1->type
+ == IMAPParser::section_text::HEADER_FIELDS) {
+
+ header tempHeader;
+ tempHeader.parse(att->nstring->value);
+
+ vmime::header& hdr = *getOrCreateHeader();
+
+ for (auto& fld : tempHeader.getFieldList()) {
+ hdr.appendField(vmime::clone(fld));
+ }
+ }
+ }
+
+ 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;
+ }
+
+ }
+ }
+
+ return changes;
+}
+
+
+shared_ptr <header> IMAPMessage::getOrCreateHeader() {
+
+ if (m_header != NULL) {
+ return m_header;
+ } else {
+ return m_header = make_shared <header>();
+ }
+}
+
+
+void IMAPMessage::setFlags(const int flags, const int mode) {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ if (!m_uid.empty()) {
+ folder->setMessageFlags(messageSet::byUID(m_uid), flags, mode);
+ } else {
+ folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode);
+ }
+}
+
+
+void IMAPMessage::constructParsedMessage(
+ const shared_ptr <bodyPart>& parentPart,
+ const shared_ptr <messageStructure>& str,
+ int level
+) {
+
+ if (level == 0) {
+
+ shared_ptr <messagePart> part = str->getPartAt(0);
+
+ // Copy header
+ shared_ptr <const header> hdr = part->getHeader();
+ parentPart->getHeader()->copyFrom(*hdr);
+
+ // Initialize body
+ parentPart->getBody()->setContents(
+ make_shared <IMAPMessagePartContentHandler>(
+ dynamicCast <IMAPMessage>(shared_from_this()),
+ part, parentPart->getBody()->getEncoding()
+ )
+ );
+
+ constructParsedMessage(parentPart, part->getStructure(), 1);
+
+ } else {
+
+ for (size_t i = 0, n = str->getPartCount() ; i < n ; ++i) {
+
+ shared_ptr <messagePart> part = str->getPartAt(i);
+
+ shared_ptr <bodyPart> childPart = make_shared <bodyPart>();
+
+ // Copy header
+ shared_ptr <const header> hdr = part->getHeader();
+ childPart->getHeader()->copyFrom(*hdr);
+
+ // Initialize body
+ childPart->getBody()->setContents(
+ make_shared <IMAPMessagePartContentHandler>(
+ dynamicCast <IMAPMessage>(shared_from_this()),
+ part, childPart->getBody()->getEncoding()
+ )
+ );
+
+ // Add child part
+ parentPart->getBody()->appendPart(childPart);
+
+ // Construct sub parts
+ constructParsedMessage(childPart, part->getStructure(), ++level);
+ }
+ }
+}
+
+
+shared_ptr <vmime::message> IMAPMessage::getParsedMessage() {
+
+ // Fetch structure
+ shared_ptr <messageStructure> structure;
+
+ try {
+
+ structure = getStructure();
+
+ } catch (exceptions::unfetched_object&) {
+
+ std::vector <shared_ptr <message> > msgs;
+ msgs.push_back(dynamicCast <IMAPMessage>(shared_from_this()));
+
+ m_folder.lock()->fetchMessages(
+ msgs, fetchAttributes(fetchAttributes::STRUCTURE), /* progress */ NULL
+ );
+
+ structure = getStructure();
+ }
+
+ // Fetch header for each part
+ fetchPartHeaderForStructure(structure);
+
+ // Construct message from structure
+ shared_ptr <vmime::message> msg = make_shared <vmime::message>();
+
+ constructParsedMessage(msg, structure);
+
+ return msg;
+}
+
+
+void IMAPMessage::renumber(const size_t number) {
+
+ m_num = number;
+}
+
+
+void IMAPMessage::setExpunged() {
+
+ m_expunged = true;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessage.hpp b/vmime-master/src/vmime/net/imap/IMAPMessage.hpp
new file mode 100644
index 0000000..6d82a3e
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessage.hpp
@@ -0,0 +1,200 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPFolder;
+
+
+/** IMAP message implementation.
+ */
+class VMIME_EXPORT IMAPMessage : public message {
+
+private:
+
+ friend class IMAPFolder;
+ friend class IMAPMessagePartContentHandler;
+
+ IMAPMessage(const IMAPMessage&) : message() { }
+
+public:
+
+ IMAPMessage(const shared_ptr <IMAPFolder>& folder, const size_t num);
+ IMAPMessage(const shared_ptr <IMAPFolder>& folder, const size_t num, const uid& uid);
+
+ ~IMAPMessage();
+
+ size_t getNumber() const;
+
+ const uid getUID() const;
+
+ /** Returns the modification sequence for this message.
+ *
+ * Every time metadata for this message changes, the modification
+ * sequence is updated, and is greater than the previous one. The
+ * server must support the CONDSTORE extension for this to be
+ * available.
+ *
+ * @return modification sequence, or zero if not supported by
+ * the underlying protocol
+ */
+ vmime_uint64 getModSequence() const;
+
+ size_t getSize() const;
+
+ bool isExpunged() const;
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const header> getHeader() const;
+
+ int getFlags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void fetchPartHeader(const shared_ptr <messagePart>& p);
+
+ shared_ptr <vmime::message> getParsedMessage();
+
+private:
+
+ /** Renumbers the message.
+ *
+ * @param number new sequence number
+ */
+ void renumber(const size_t number);
+
+ /** Marks the message as expunged.
+ */
+ void setExpunged();
+
+ /** Processes the parsed response to fill in the attributes
+ * and metadata of this message.
+ *
+ * @param options one or more fetch options (see folder::fetchAttributes)
+ * @param msgData pointer to message_data component of the parsed response
+ * @return a combination of flags that specify what changed exactly on
+ * this message (see events::messageChangedEvent::Types)
+ */
+ int processFetchResponse(const fetchAttributes& options, const IMAPParser::message_data& msgData);
+
+ /** Recursively fetch part header for all parts in the structure.
+ *
+ * @param str structure for which to fetch parts headers
+ */
+ void fetchPartHeaderForStructure(const shared_ptr <messageStructure>& str);
+
+ /** Recursively contruct parsed message from structure.
+ * Called by getParsedMessage().
+ *
+ * @param parentPart root body part (the message)
+ * @param str structure for which to construct part
+ * @param level current nesting level (0 is root)
+ */
+ void constructParsedMessage(
+ const shared_ptr <bodyPart>& parentPart,
+ const shared_ptr <messageStructure>& str,
+ int level = 0
+ );
+
+
+ enum ExtractFlags
+ {
+ EXTRACT_HEADER = 0x1,
+ EXTRACT_BODY = 0x2,
+ EXTRACT_PEEK = 0x10
+ };
+
+ size_t extractImpl(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const int extractFlags
+ ) const;
+
+
+ shared_ptr <header> getOrCreateHeader();
+
+
+ void onFolderClosed();
+
+ weak_ptr <IMAPFolder> m_folder;
+
+ size_t m_num;
+ size_t m_size;
+ int m_flags;
+ bool m_expunged;
+ uid m_uid;
+ vmime_uint64 m_modseq;
+
+ shared_ptr <header> m_header;
+ shared_ptr <messageStructure> m_structure;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp b/vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp
new file mode 100644
index 0000000..ed2c0bd
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp
@@ -0,0 +1,225 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPMessagePart.hpp"
+#include "vmime/net/imap/IMAPMessageStructure.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPMessagePart::IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t 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
+ );
+}
+
+namespace {
+ template<typename T>
+ vmime::string getPartName(const T& body_type) {
+ if (const auto* pparam = body_type->body_fields->body_fld_param.get()) {
+ for (const auto& param : pparam->items) {
+ if (param->string1->value == "NAME") {
+ return param->string2->value;
+ }
+ }
+ }
+
+ return {};
+ }
+}
+
+
+IMAPMessagePart::IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t 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;
+
+ m_name = getPartName(part->body_type_text);
+
+ } 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_name = getPartName(part->body_type_basic);
+ }
+
+ if (part->body_ext_1part && part->body_ext_1part->body_fld_dsp) {
+ auto *cdisp = part->body_ext_1part->body_fld_dsp->str();
+ if (cdisp) {
+ m_dispType = contentDisposition(cdisp->value);
+ }
+ }
+
+ m_structure = null;
+}
+
+
+shared_ptr <const messageStructure> IMAPMessagePart::getStructure() const {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return IMAPMessageStructure::emptyStructure();
+ }
+}
+
+
+shared_ptr <messageStructure> IMAPMessagePart::getStructure() {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return IMAPMessageStructure::emptyStructure();
+ }
+}
+
+
+shared_ptr <const IMAPMessagePart> IMAPMessagePart::getParent() const {
+
+ return m_parent.lock();
+}
+
+
+const mediaType& IMAPMessagePart::getType() const {
+
+ return m_mediaType;
+}
+
+
+const contentDisposition &IMAPMessagePart::getDisposition() const {
+
+ return m_dispType;
+}
+
+
+size_t IMAPMessagePart::getSize() const {
+
+ return m_size;
+}
+
+
+size_t IMAPMessagePart::getNumber() const {
+
+ return m_number;
+}
+
+
+string IMAPMessagePart::getName() const {
+
+ return m_name;
+}
+
+
+shared_ptr <const header> IMAPMessagePart::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ } else {
+ return m_header;
+ }
+}
+
+
+// static
+shared_ptr <IMAPMessagePart> IMAPMessagePart::create(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body* body
+) {
+
+ if (body->body_type_mpart) {
+
+ auto part = make_shared <IMAPMessagePart>(parent, number, body->body_type_mpart.get());
+ part->m_structure = make_shared <IMAPMessageStructure>(part, body->body_type_mpart->list);
+
+ return part;
+
+ } else {
+
+ return make_shared <IMAPMessagePart>(parent, number, body->body_type_1part.get());
+ }
+}
+
+
+header& IMAPMessagePart::getOrCreateHeader() {
+
+ if (m_header) {
+ return *m_header;
+ } else {
+ return *(m_header = make_shared <header>());
+ }
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp b/vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp
new file mode 100644
index 0000000..34ea172
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp
@@ -0,0 +1,108 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGEPART_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGEPART_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/message.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPMessageStructure;
+
+
+class VMIME_EXPORT IMAPMessagePart : public messagePart {
+
+public:
+
+ IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body_type_mpart* mpart
+ );
+
+ IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body_type_1part* part
+ );
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const IMAPMessagePart> getParent() const;
+
+ const mediaType& getType() const;
+ const contentDisposition &getDisposition() const;
+ size_t getSize() const;
+ size_t getNumber() const;
+ string getName() const;
+
+ shared_ptr <const header> getHeader() const;
+
+
+ static shared_ptr <IMAPMessagePart> create(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body* body
+ );
+
+
+ header& getOrCreateHeader();
+
+private:
+
+ shared_ptr <IMAPMessageStructure> m_structure;
+ weak_ptr <IMAPMessagePart> m_parent;
+ shared_ptr <header> m_header;
+
+ size_t m_number;
+ size_t m_size;
+ string m_name;
+ mediaType m_mediaType;
+ contentDisposition m_dispType;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGEPART_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp
new file mode 100644
index 0000000..85f6cb6
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp
@@ -0,0 +1,227 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPMessagePartContentHandler.hpp"
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPMessagePartContentHandler::IMAPMessagePartContentHandler(
+ const shared_ptr <IMAPMessage>& msg,
+ const shared_ptr <messagePart>& part,
+ const vmime::encoding& encoding
+)
+ : m_message(msg),
+ m_part(part),
+ m_encoding(encoding) {
+
+}
+
+
+shared_ptr <contentHandler> IMAPMessagePartContentHandler::clone() const {
+
+ return make_shared <IMAPMessagePartContentHandler>(
+ m_message.lock(), m_part.lock(), m_encoding
+ );
+}
+
+
+void IMAPMessagePartContentHandler::generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength
+) const {
+
+ shared_ptr <IMAPMessage> msg = m_message.lock();
+ shared_ptr <messagePart> part = m_part.lock();
+
+ // Data is already encoded
+ if (isEncoded()) {
+
+ // The data is already encoded but the encoding specified for
+ // the generation is different from the current one. We need
+ // to re-encode data: decode from input buffer to temporary
+ // buffer, and then re-encode to output stream...
+ if (m_encoding != enc) {
+
+ // Extract part contents to temporary buffer
+ std::ostringstream oss;
+ utility::outputStreamAdapter tmp(oss);
+
+ msg->extractPart(part, tmp, NULL);
+
+ // Decode to another temporary buffer
+ utility::inputStreamStringAdapter in(oss.str());
+
+ std::ostringstream oss2;
+ utility::outputStreamAdapter tmp2(oss2);
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+ theDecoder->decode(in, tmp2);
+
+ // Reencode to output stream
+ string str = oss2.str();
+ utility::inputStreamStringAdapter tempIn(str);
+
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ theEncoder->encode(tempIn, os);
+
+ // No encoding to perform
+ } else {
+
+ msg->extractPart(part, os);
+ }
+
+ // Need to encode data before
+ } else {
+
+ // Extract part contents to temporary buffer
+ std::ostringstream oss;
+ utility::outputStreamAdapter tmp(oss);
+
+ msg->extractPart(part, tmp, NULL);
+
+ // Encode temporary buffer to output stream
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ utility::inputStreamStringAdapter is(oss.str());
+
+ theEncoder->encode(is, os);
+ }
+}
+
+
+void IMAPMessagePartContentHandler::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ shared_ptr <IMAPMessage> msg = m_message.lock();
+ shared_ptr <messagePart> part = m_part.lock();
+
+ // No decoding to perform
+ if (!isEncoded()) {
+
+ msg->extractImpl(part, os, progress, 0, -1, IMAPMessage::EXTRACT_BODY);
+
+ // Need to decode data
+ } else {
+
+ // Extract part contents to temporary buffer
+ std::ostringstream oss;
+ utility::outputStreamAdapter tmp(oss);
+
+ msg->extractImpl(part, tmp, NULL, 0, -1, IMAPMessage::EXTRACT_BODY);
+
+ // Encode temporary buffer to output stream
+ utility::inputStreamStringAdapter is(oss.str());
+ utility::progressListenerSizeAdapter plsa(progress, getLength());
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+ theDecoder->decode(is, os, &plsa);
+ }
+}
+
+
+void IMAPMessagePartContentHandler::extractRaw(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ shared_ptr <IMAPMessage> msg = m_message.lock();
+ shared_ptr <messagePart> part = m_part.lock();
+
+ msg->extractPart(part, os, progress);
+}
+
+
+size_t IMAPMessagePartContentHandler::getLength() const {
+
+ return m_part.lock()->getSize();
+}
+
+
+bool IMAPMessagePartContentHandler::isEncoded() const {
+
+ return m_encoding != NO_ENCODING;
+}
+
+
+const vmime::encoding& IMAPMessagePartContentHandler::getEncoding() const {
+
+ return m_encoding;
+}
+
+
+bool IMAPMessagePartContentHandler::isEmpty() const {
+
+ return getLength() == 0;
+}
+
+
+bool IMAPMessagePartContentHandler::isBuffered() const {
+
+ return true;
+}
+
+
+void IMAPMessagePartContentHandler::setContentTypeHint(const mediaType& type) {
+
+ m_contentType = type;
+}
+
+
+const mediaType IMAPMessagePartContentHandler::getContentTypeHint() const {
+
+ return m_contentType;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp
new file mode 100644
index 0000000..17f53e3
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGEPARTCONTENTHANDLER_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGEPARTCONTENTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/contentHandler.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class VMIME_EXPORT IMAPMessagePartContentHandler : public contentHandler {
+
+public:
+
+ IMAPMessagePartContentHandler(
+ const shared_ptr <IMAPMessage>& msg,
+ const shared_ptr <messagePart>& part,
+ const vmime::encoding& encoding
+ );
+
+ shared_ptr <contentHandler> clone() const;
+
+ void generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength = lineLengthLimits::infinite
+ ) const;
+
+ void extract(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+ void extractRaw(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+
+ size_t getLength() const;
+
+ bool isEncoded() const;
+
+ const vmime::encoding& getEncoding() const;
+
+ bool isEmpty() const;
+
+ bool isBuffered() const;
+
+ void setContentTypeHint(const mediaType& type);
+ const mediaType getContentTypeHint() const;
+
+private:
+
+ weak_ptr <IMAPMessage> m_message;
+ weak_ptr <messagePart> m_part;
+
+ vmime::encoding m_encoding;
+ vmime::mediaType m_contentType;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGEPARTCONTENTHANDLER_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp
new file mode 100644
index 0000000..c7ee809
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp
@@ -0,0 +1,94 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPMessageStructure.hpp"
+#include "vmime/net/imap/IMAPMessagePart.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPMessageStructure::IMAPMessageStructure() {
+}
+
+
+IMAPMessageStructure::IMAPMessageStructure(const IMAPParser::body* body) {
+
+ m_parts.push_back(IMAPMessagePart::create(null, 0, body));
+}
+
+
+IMAPMessageStructure::IMAPMessageStructure(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const std::vector <std::unique_ptr <IMAPParser::body>>& list
+) {
+
+ size_t number = 0;
+
+ for (auto it = list.begin() ; it != list.end() ; ++it, ++number) {
+ m_parts.push_back(IMAPMessagePart::create(parent, number, it->get()));
+ }
+}
+
+
+shared_ptr <const messagePart> IMAPMessageStructure::getPartAt(const size_t x) const {
+
+ return m_parts[x];
+}
+
+
+shared_ptr <messagePart> IMAPMessageStructure::getPartAt(const size_t x) {
+
+ return m_parts[x];
+}
+
+
+size_t IMAPMessageStructure::getPartCount() const {
+
+ return m_parts.size();
+}
+
+
+// static
+shared_ptr <IMAPMessageStructure> IMAPMessageStructure::emptyStructure() {
+
+ static shared_ptr <IMAPMessageStructure> emptyStructure = make_shared <IMAPMessageStructure>();
+ return emptyStructure;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp
new file mode 100644
index 0000000..ee1eac4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGESTRUCTURE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGESTRUCTURE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/message.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPMessagePart;
+
+
+class VMIME_EXPORT IMAPMessageStructure : public messageStructure {
+
+public:
+
+ IMAPMessageStructure();
+ IMAPMessageStructure(const IMAPParser::body* body);
+ IMAPMessageStructure(const shared_ptr <IMAPMessagePart>& parent, const std::vector <std::unique_ptr <IMAPParser::body>>& list);
+
+ shared_ptr <const messagePart> getPartAt(const size_t x) const;
+ shared_ptr <messagePart> getPartAt(const size_t x);
+ size_t getPartCount() const;
+
+ static shared_ptr <IMAPMessageStructure> emptyStructure();
+
+private:
+
+ std::vector <shared_ptr <IMAPMessagePart> > m_parts;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGESTRUCTURE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPParser.hpp b/vmime-master/src/vmime/net/imap/IMAPParser.hpp
new file mode 100644
index 0000000..281fcb6
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPParser.hpp
@@ -0,0 +1,4986 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPPARSER_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPPARSER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/base.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/charset.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+#include "vmime/utility/encoder/b64Encoder.hpp"
+#include "vmime/utility/encoder/qpEncoder.hpp"
+
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/net/imap/IMAPTag.hpp"
+
+#include <vector>
+#include <stdexcept>
+#include <memory>
+
+
+//#define DEBUG_RESPONSE 1
+
+
+#if DEBUG_RESPONSE
+# include <iostream>
+#endif
+
+
+/** Make the parsing of a component fail.
+ */
+#define VIMAP_PARSER_FAIL() \
+ { \
+ parser.m_errorResponseLine = makeResponseLine(getComponentName(), line, pos); \
+ return false; \
+ }
+
+/** Make the parsing of a component fail if a condition is not matched.
+ * If the specified expression does not resolve to "true", the parsing
+ * will fail.
+ *
+ * @param cond condition expression
+ */
+#define VIMAP_PARSER_FAIL_UNLESS(cond) \
+ if (!(cond)) \
+ { \
+ VIMAP_PARSER_FAIL(); \
+ }
+
+/** Check for a token and advance.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_CHECK(type) \
+ VIMAP_PARSER_FAIL_UNLESS(parser.check <type>(line, &pos))
+
+/** Check for an optional token and advance.
+ * If the token is not matched, parsing will continue anyway.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_TRY_CHECK(type) \
+ (parser.check <type>(line, &pos))
+
+/** Get a token and advance.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ * @param variable variable which will receive pointer to the retrieved token
+ */
+#define VIMAP_PARSER_GET(type, variable) \
+ { \
+ variable.reset(parser.get <type>(line, &pos)); \
+ VIMAP_PARSER_FAIL_UNLESS(variable.get()); \
+ }
+
+/** Get an optional token and advance.
+ * If the token is not matched, parsing will continue anyway.
+ */
+#define VIMAP_PARSER_TRY_GET(type, variable) \
+ (variable.reset(parser.get <type>(line, &pos)), variable.get())
+
+/** Get an optional token and advance. If found, token will be pushed back
+ * to a vector. If the token is not matched, stopInstr will be executed.
+ *
+ * @param type token class
+ * @param variable variable of type std::vector<> to which the retrieved
+ * token will be pushed
+ * @param stopInstr instruction to execute if token is not found
+ */
+#define VIMAP_PARSER_TRY_GET_PUSHBACK_OR_ELSE(type, variable, stopInstr) \
+ { \
+ std::unique_ptr <type> v; \
+ try \
+ { \
+ v.reset(parser.get <type>(line, &pos)); \
+ if (!v) \
+ { \
+ stopInstr; \
+ } \
+ variable.push_back(std::move(v)); \
+ } \
+ catch (...) \
+ { \
+ throw; \
+ } \
+ }
+
+/** Get a token and advance. Token will be pushed back to a vector.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ * @param variable variable of type std::vector<> to which the retrieved
+ * token will be pushed
+ */
+#define VIMAP_PARSER_GET_PUSHBACK(type, variable) \
+ VIMAP_PARSER_TRY_GET_PUSHBACK_OR_ELSE(type, variable, VIMAP_PARSER_FAIL())
+
+
+/** Check for a token which takes an argument and advance.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_CHECK_WITHARG(type, arg) \
+ VIMAP_PARSER_FAIL_UNLESS(parser.checkWithArg <type>(line, &pos, arg))
+
+/** Check for an optional token which takes an argument and advance.
+ * If the token is not matched, parsing will continue anyway.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_TRY_CHECK_WITHARG(type, arg) \
+ (parser.checkWithArg <type>(line, &pos, arg))
+
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+#if DEBUG_RESPONSE
+ static int IMAPParserDebugResponse_level = 0;
+ static std::vector <string> IMAPParserDebugResponse_stack;
+
+ class IMAPParserDebugResponse {
+
+ public:
+
+ IMAPParserDebugResponse(
+ const string& name,
+ string& line,
+ const size_t currentPos,
+ const bool &result
+ )
+ : m_name(name),
+ m_line(line),
+ m_pos(currentPos),
+ m_result(result) {
+
+ ++IMAPParserDebugResponse_level;
+ IMAPParserDebugResponse_stack.push_back(name);
+
+ for (int i = 0 ; i < IMAPParserDebugResponse_level ; ++i) {
+ std::cout << " ";
+ }
+
+ std::cout << "ENTER(" << m_name << "), pos=" << m_pos;
+ std::cout << std::endl;
+
+ for (std::vector <string>::iterator it = IMAPParserDebugResponse_stack.begin() ;
+ it != IMAPParserDebugResponse_stack.end() ; ++it) {
+
+ std::cout << "> " << *it << " ";
+ }
+
+ std::cout << std::endl;
+ std::cout << string(m_line.begin() + (m_pos < 30 ? 0U : m_pos - 30),
+ m_line.begin() + std::min(m_line.length(), m_pos + 30)) << std::endl;
+
+ for (size_t i = (m_pos < 30 ? m_pos : (m_pos - (m_pos - 30))) ; i != 0 ; --i) {
+ std::cout << " ";
+ }
+
+ std::cout << "^" << std::endl;
+ }
+
+ ~IMAPParserDebugResponse() {
+
+ for (int i = 0 ; i < IMAPParserDebugResponse_level ; ++i) {
+ std::cout << " ";
+ }
+
+ std::cout << "LEAVE(" << m_name << "), result=";
+ std::cout << (m_result ? "TRUE" : "FALSE") << ", pos=" << m_pos;
+ std::cout << std::endl;
+
+ --IMAPParserDebugResponse_level;
+ IMAPParserDebugResponse_stack.pop_back();
+ }
+
+ private:
+
+ const string m_name;
+ string m_line;
+ size_t m_pos;
+ const bool& m_result;
+ };
+
+
+ #define DEBUG_ENTER_COMPONENT(x, result) \
+ IMAPParserDebugResponse dbg(x, line, *currentPos, result)
+
+ #define DEBUG_FOUND(x, y) \
+ std::cout << "FOUND: " << x << ": " << y << std::endl;
+#else
+ #define DEBUG_ENTER_COMPONENT(x, result)
+ #define DEBUG_FOUND(x, y)
+#endif
+
+
+class VMIME_EXPORT IMAPParser : public object {
+
+public:
+
+ IMAPParser()
+ : m_progress(NULL),
+ m_strict(false),
+ m_literalHandler(NULL) {
+
+ }
+
+ ~IMAPParser() {
+
+ for (auto it = m_pendingResponses.begin() ; it != m_pendingResponses.end() ; ++it) {
+ delete it->second;
+ }
+ }
+
+
+ /** Set the socket currently used by this parser to receive data
+ * from server.
+ *
+ * @param sok socket
+ */
+ void setSocket(const shared_ptr <socket>& sok) {
+
+ m_socket = sok;
+ }
+
+ /** Set the timeout handler currently used by this parser.
+ *
+ * @param toh timeout handler
+ */
+ void setTimeoutHandler(const shared_ptr <timeoutHandler>& toh) {
+
+ m_timeoutHandler = toh;
+ }
+
+ /** Set the tracer currently used by this parser.
+ *
+ * @param tr tracer
+ */
+ void setTracer(const shared_ptr <tracer>& tr) {
+
+ m_tracer = tr;
+ }
+
+ /** Set whether we operate in strict mode (this may not work
+ * with some servers which are not fully standard-compliant).
+ *
+ * @param strict true to operate in strict mode, or false
+ * to operate in default, relaxed mode
+ */
+ void setStrict(const bool strict) {
+
+ m_strict = strict;
+ }
+
+ /** Return true if the parser operates in strict mode, or
+ * false otherwise.
+ *
+ * @return true if we are in strict mode, false otherwise
+ */
+ bool isStrict() const {
+
+ return m_strict;
+ }
+
+
+
+ //
+ // literalHandler : literal content handler
+ //
+
+ class component;
+
+ class literalHandler {
+
+ public:
+
+ virtual ~literalHandler() { }
+
+
+ // Abstract target class
+ class target {
+
+ protected:
+
+ target(utility::progressListener* progress) : m_progress(progress) {}
+ target(const target&) {}
+
+ public:
+
+ virtual ~target() { }
+
+
+ utility::progressListener* progressListener() { return (m_progress); }
+
+ virtual void putData(const string& chunk) = 0;
+
+ virtual size_t getBytesWritten() const = 0;
+
+ private:
+
+ utility::progressListener* m_progress;
+ };
+
+
+ // Target: put in a string
+ class targetString : public target {
+
+ public:
+
+ targetString(utility::progressListener* progress, vmime::string& str)
+ : target(progress), m_string(str), m_bytesWritten(0) { }
+
+ const vmime::string& string() const { return (m_string); }
+ vmime::string& string() { return (m_string); }
+
+
+ void putData(const vmime::string& chunk) {
+
+ m_string += chunk;
+ m_bytesWritten += chunk.length();
+ }
+
+ size_t getBytesWritten() const {
+
+ return m_bytesWritten;
+ }
+
+ private:
+
+ vmime::string& m_string;
+ size_t m_bytesWritten;
+ };
+
+
+ // Target: redirect to an output stream
+ class targetStream : public target {
+
+ public:
+
+ targetStream(
+ utility::progressListener* progress,
+ utility::outputStream& stream
+ )
+ : target(progress),
+ m_stream(stream),
+ m_bytesWritten(0) {
+
+ }
+
+ const utility::outputStream& stream() const { return (m_stream); }
+ utility::outputStream& stream() { return (m_stream); }
+
+
+ void putData(const string& chunk) {
+
+ m_stream.write(chunk.data(), chunk.length());
+ m_bytesWritten += chunk.length();
+ }
+
+ size_t getBytesWritten() const {
+
+ return m_bytesWritten;
+ }
+
+ private:
+
+ utility::outputStream& m_stream;
+ size_t m_bytesWritten;
+ };
+
+
+ // Called when the parser needs to know what to do with a literal
+ // . comp: the component in which we are at this moment
+ // . data: data specific to the component (may not be used)
+ //
+ // Returns :
+ // . == NULL to put the literal into the response
+ // . != NULL to redirect the literal to the specified target
+
+ virtual shared_ptr <target> targetFor(const component& comp, const int data) = 0;
+ };
+
+
+ //
+ // Base class for a terminal or a non-terminal
+ //
+
+ class component {
+
+ public:
+
+ component() { }
+ virtual ~component() { }
+
+ virtual const string getComponentName() const = 0;
+
+ bool parse(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ bool res = false;
+ DEBUG_ENTER_COMPONENT(getComponentName(), res);
+ res = parseImpl(parser, line, currentPos);
+ return res;
+ }
+
+ virtual bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) = 0;
+
+
+ const string makeResponseLine(
+ const string& comp,
+ const string& line,
+ const size_t pos
+ ) {
+
+#if DEBUG_RESPONSE
+ if (pos > line.length()) {
+ std::cout << "WARNING: component::makeResponseLine(): pos > line.length()" << std::endl;
+ }
+#endif
+
+ string result(line.substr(0, pos));
+ result += "[^]"; // indicates current parser position
+ result += line.substr(pos, line.length());
+ if (!comp.empty()) result += " [" + comp + "]";
+
+ return (result);
+ }
+ };
+
+
+#define COMPONENT_ALIAS(parent, name) \
+ class name : public parent { \
+ virtual const string getComponentName() const { return #name; } \
+ public: \
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) { \
+ return parent::parseImpl(parser, line, currentPos); \
+ } \
+ }
+
+#define DECLARE_COMPONENT(name) \
+ class name : public component { \
+ virtual const string getComponentName() const { return #name; } \
+ public:
+
+
+ //
+ // Parse one character
+ //
+
+ template <char C>
+ class one_char : public component {
+
+ public:
+
+ const string getComponentName() const {
+
+ return string("one_char <") + C + ">";
+ }
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ const size_t pos = *currentPos;
+
+ if (pos < line.length() && line[pos] == C) {
+ *currentPos = pos + 1;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ DECLARE_COMPONENT(SPACE)
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t')) {
+ ++pos;
+ }
+
+ if (pos > *currentPos) {
+ *currentPos = pos;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ //
+ // CR ::= <ASCII CR, carriage return, 0x0D>
+ // LF ::= <ASCII LF, line feed, 0x0A>
+ // CRLF ::= CR LF
+ //
+
+ DECLARE_COMPONENT(CRLF)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ if (pos + 1 < line.length() &&
+ line[pos] == 0x0d && line[pos + 1] == 0x0a) {
+
+ *currentPos = pos + 2;
+ return true;
+
+ } else {
+
+ return false;
+ }
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ // CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ //
+ // tag ::= 1*<any ATOM_CHAR except "+"> (named "xtag")
+ //
+
+ DECLARE_COMPONENT(xtag)
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ bool end = false;
+
+ tagString.reserve(10);
+
+ while (!end && pos < line.length()) {
+
+ const unsigned char c = line[pos];
+
+ switch (c) {
+
+ case '+':
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f) {
+ end = true;
+ } else {
+ tagString += c;
+ ++pos;
+ }
+
+ break;
+ }
+ }
+
+ *currentPos = pos;
+ return true;
+ }
+
+ string tagString;
+ };
+
+
+ //
+ // digit ::= "0" / digit_nz
+ // digit_nz ::= "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
+ //
+ // number ::= 1*digit
+ // ;; Unsigned 32-bit integer
+ // ;; (0 <= n < 4,294,967,296)
+ //
+
+ DECLARE_COMPONENT(number)
+
+ number(const bool nonZero = false)
+ : value(0),
+ m_nonZero(nonZero) {
+
+ }
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ bool valid = true;
+ unsigned int val = 0;
+
+ while (valid && pos < line.length()) {
+
+ const char c = line[pos];
+
+ if (c >= '0' && c <= '9') {
+ val = (val * 10) + (c - '0');
+ ++pos;
+ } else {
+ valid = false;
+ }
+ }
+
+ // Check for non-null length (and for non-zero number)
+ if (!(m_nonZero && val == 0) && pos != *currentPos) {
+ value = val;
+ *currentPos = pos;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ unsigned long value;
+
+ private:
+
+ const bool m_nonZero;
+ };
+
+
+ // nz_number ::= digit_nz *digit
+ // ;; Non-zero unsigned 32-bit integer
+ // ;; (0 < n < 4,294,967,296)
+ //
+
+ class nz_number : public number {
+
+ public:
+
+ nz_number()
+ : number(true) {
+
+ }
+ };
+
+
+ //
+ // uniqueid ::= nz_number
+ // ;; Strictly ascending
+ //
+
+ class uniqueid : public nz_number {
+
+ public:
+
+ uniqueid()
+ : nz_number() {
+
+ }
+ };
+
+
+ // uid-range = (uniqueid ":" uniqueid)
+ // ; two uniqueid values and all values
+ // ; between these two regards of order.
+ // ; Example: 2:4 and 4:2 are equivalent.
+
+ DECLARE_COMPONENT(uid_range)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(uniqueid, uniqueid1);
+ VIMAP_PARSER_CHECK(one_char <':'>);
+ VIMAP_PARSER_GET(uniqueid, uniqueid2);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <uniqueid> uniqueid1;
+ std::unique_ptr <uniqueid> uniqueid2;
+ };
+
+
+ //
+ // uid-set = (uniqueid / uid-range) *("," uid-set)
+ //
+
+ DECLARE_COMPONENT(uid_set)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // We have either a 'uid_range' or a 'uniqueid'
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::uid_range, uid_range)) {
+ VIMAP_PARSER_GET(IMAPParser::uniqueid, uniqueid);
+ }
+
+ // And maybe another 'uid-set' following
+ if (VIMAP_PARSER_TRY_CHECK(one_char <','>)) {
+ VIMAP_PARSER_GET(IMAPParser::uid_set, next_uid_set);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::uniqueid> uniqueid;
+ std::unique_ptr <IMAPParser::uid_range> uid_range;
+
+ std::unique_ptr <IMAPParser::uid_set> next_uid_set;
+ };
+
+
+ //
+ // text ::= 1*TEXT_CHAR
+ //
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ //
+
+ DECLARE_COMPONENT(text)
+
+ text(bool allow8bits = false, const char except = 0)
+ : m_allow8bits(allow8bits),
+ m_except(except) {
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ size_t len = 0;
+
+ if (m_allow8bits || !parser.isStrict()) {
+
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ if (c == 0x00 || c == 0x0d || c == 0x0a || c == except) {
+ end = true;
+ } else {
+ ++pos;
+ ++len;
+ }
+ }
+
+ } else {
+
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ if (c < 0x01 || c > 0x7f || c == 0x0d || c == 0x0a || c == except) {
+ end = true;
+ } else {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len == 0) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, value.begin());
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ string value;
+
+ private:
+
+ const bool m_allow8bits;
+ const char m_except;
+ };
+
+
+ class text8 : public text {
+
+ public:
+
+ text8() : text(true) {
+
+ }
+ };
+
+
+ template <char C>
+ class text_except : public text {
+
+ public:
+
+ text_except() : text(false, C) {
+
+ }
+ };
+
+
+ template <char C>
+ class text8_except : public text {
+
+ public:
+
+ text8_except() : text(true, C) {
+
+ }
+ };
+
+
+ //
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ DECLARE_COMPONENT(QUOTED_CHAR)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ const unsigned char c = static_cast <unsigned char>(pos < line.length() ? line[pos] : 0);
+
+ if (c >= 0x01 && c <= 0x7f && // 0x01 - 0x7f
+ c != '"' && c != '\\' && // quoted_specials
+ c != '\r' && c != '\n') { // CR and LF
+
+ value = c;
+ *currentPos = pos + 1;
+
+ } else if (c == '\\' && pos + 1 < line.length() &&
+ (line[pos + 1] == '"' || line[pos + 1] == '\\')) {
+
+ value = line[pos + 1];
+ *currentPos = pos + 2;
+
+ } else {
+
+ VIMAP_PARSER_FAIL();
+ }
+
+ return true;
+ }
+
+
+ char value;
+ };
+
+
+ //
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ DECLARE_COMPONENT(quoted_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ size_t len = 0;
+ bool valid = false;
+
+ value.reserve(line.length() - pos);
+
+ for (bool end = false, quoted = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ if (quoted) {
+
+ if (c == '"' || c == '\\') {
+ value += c;
+ } else {
+ value += '\\';
+ value += c;
+ }
+
+ quoted = false;
+
+ ++pos;
+ ++len;
+
+ } else {
+
+ if (c == '\\') {
+
+ quoted = true;
+
+ ++pos;
+ ++len;
+
+ } else if (c == '"') {
+
+ valid = true;
+ end = true;
+
+ } else if (c >= 0x01 && c <= 0x7f && // CHAR
+ c != 0x0a && c != 0x0d) { // CR and LF
+
+ value += c;
+
+ ++pos;
+ ++len;
+
+ } else {
+
+ valid = false;
+ end = true;
+ }
+ }
+ }
+
+ if (!valid) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ string value;
+ };
+
+
+ //
+ // nil ::= "NIL"
+ //
+
+ DECLARE_COMPONENT(NIL)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "nil");
+
+ *currentPos = pos;
+
+ return true;
+ }
+ };
+
+
+ //
+ // string ::= quoted / literal ----> named 'xstring'
+ //
+ // nil ::= "NIL"
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // literal ::= "{" number "}" CRLF *CHAR8
+ // ;; Number represents the number of CHAR8 octets
+ // CHAR8 ::= <any 8-bit octet except NUL, 0x01 - 0xff>
+ //
+
+ DECLARE_COMPONENT(xstring)
+
+ xstring(
+ const bool canBeNIL = false,
+ component* comp = NULL,
+ const int data = 0
+ )
+ : isNIL(true),
+ m_canBeNIL(canBeNIL),
+ m_component(comp),
+ m_data(data) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (m_canBeNIL &&
+ VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "nil")) {
+
+ // NIL
+ isNIL = true;
+
+ } else {
+
+ pos = *currentPos;
+
+ isNIL = false;
+
+ // quoted ::= <"> *QUOTED_CHAR <">
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'"'>)) {
+
+ shared_ptr <quoted_text> text;
+ VIMAP_PARSER_GET(quoted_text, text);
+ VIMAP_PARSER_CHECK(one_char <'"'>);
+
+ if (parser.m_literalHandler != NULL) {
+
+ shared_ptr <literalHandler::target> target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL) {
+
+ value = "[literal-handler]";
+
+ const size_t length = text->value.length();
+ utility::progressListener* progress = target->progressListener();
+
+ if (progress) {
+ progress->start(length);
+ }
+
+ target->putData(text->value);
+
+ if (progress) {
+ progress->progress(length, length);
+ progress->stop(length);
+ }
+
+ } else {
+
+ value = text->value;
+ }
+
+ } else {
+
+ value = text->value;
+ }
+
+ DEBUG_FOUND("string[quoted]", "<length=" << value.length() << ", value='" << value << "'>");
+
+ // literal ::= "{" number "}" CRLF *CHAR8
+ } else {
+
+ VIMAP_PARSER_CHECK(one_char <'{'>);
+
+ shared_ptr <number> num;
+ VIMAP_PARSER_GET(number, num);
+
+ const size_t length = num->value;
+
+ VIMAP_PARSER_CHECK(one_char <'}'> );
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+
+ if (parser.m_literalHandler != NULL) {
+
+ shared_ptr <literalHandler::target> target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL) {
+
+ value = "[literal-handler]";
+
+ parser.m_progress = target->progressListener();
+ parser.readLiteral(*target, length);
+ parser.m_progress = NULL;
+
+ } else {
+
+ literalHandler::targetString target(NULL, value);
+ parser.readLiteral(target, length);
+ }
+
+ } else {
+
+ literalHandler::targetString target(NULL, value);
+ parser.readLiteral(target, length);
+ }
+
+ line += parser.readLine();
+
+ DEBUG_FOUND("string[literal]", "<length=" << length << ", value='" << value << "'>");
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ bool isNIL;
+ string value;
+
+ private:
+
+ bool m_canBeNIL;
+
+ component* m_component;
+ const int m_data;
+ };
+
+
+ //
+ // nstring ::= string / nil
+ //
+
+ class nstring : public xstring {
+
+ public:
+
+ const string getComponentName() const {
+
+ return "nstring";
+ }
+
+ nstring(component* comp = NULL, const int data = 0)
+ : xstring(true, comp, data) {
+
+ }
+ };
+
+
+ //
+ // astring ::= atom / string
+ //
+
+ DECLARE_COMPONENT(astring)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ std::unique_ptr <xstring> str;
+ VIMAP_PARSER_TRY_GET(xstring, str);
+
+ if (str) {
+ value = str->value;
+ } else {
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+ value = at->value;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ string value;
+ };
+
+
+ //
+ // atom ::= 1*ATOM_CHAR
+ //
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / 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>
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ DECLARE_COMPONENT(atom)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ size_t len = 0;
+
+ for (bool end = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ switch (c) {
+
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ case '[':
+ case ']': // for "special_atom"
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f) {
+ end = true;
+ } else {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len != 0) {
+
+ value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, value.begin());
+
+ *currentPos = pos;
+
+ } else {
+
+ VIMAP_PARSER_FAIL();
+ }
+
+ return true;
+ }
+
+
+ string value;
+ };
+
+
+ //
+ // special atom (eg. "CAPABILITY", "FLAGS", "STATUS"...)
+ //
+ // " Except as noted otherwise, all alphabetic characters are case-
+ // insensitive. The use of upper or lower case characters to define
+ // token strings is for editorial clarity only. Implementations MUST
+ // accept these strings in a case-insensitive fashion. "
+ //
+
+ class special_atom : public atom {
+
+ public:
+
+ const std::string getComponentName() const {
+
+ return string("special_atom <") + m_string + ">";
+ }
+
+ special_atom(const char* str)
+ : m_string(str) { // 'string' must be in lower-case
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!atom::parseImpl(parser, line, &pos)) {
+ return false;
+ }
+
+ const char* cmp = value.c_str();
+ const char* with = m_string;
+
+ bool ok = true;
+
+ while (ok && *cmp && *with) {
+
+ ok = (std::tolower(*cmp, std::locale()) == *with);
+
+ ++cmp;
+ ++with;
+ }
+
+ if (!ok || *cmp || *with) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ private:
+
+ const char* m_string;
+ };
+
+
+ //
+ // text_mime2 ::= "=?" <charset> "?" <encoding> "?" <encoded-text> "?="
+ // ;; Syntax defined in [MIME-HDRS]
+ //
+
+ DECLARE_COMPONENT(text_mime2)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ std::unique_ptr <atom> theCharset, theEncoding;
+ std::unique_ptr <text> theText;
+
+ VIMAP_PARSER_CHECK(one_char <'='> );
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+
+ VIMAP_PARSER_GET(atom, theCharset);
+
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+
+ VIMAP_PARSER_GET(atom, theEncoding);
+
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+
+ VIMAP_PARSER_GET(text8_except <'?'> , theText);
+
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+ VIMAP_PARSER_CHECK(one_char <'='> );
+
+ charset = theCharset->value;
+
+ // Decode text
+ scoped_ptr <utility::encoder::encoder> theEncoder;
+
+ if (theEncoding->value[0] == 'q' || theEncoding->value[0] == 'Q') {
+
+ // Quoted-printable
+ theEncoder.reset(new utility::encoder::qpEncoder());
+ theEncoder->getProperties()["rfc2047"] = true;
+
+ } else if (theEncoding->value[0] == 'b' || theEncoding->value[0] == 'B') {
+
+ // Base64
+ theEncoder.reset(new utility::encoder::b64Encoder());
+ }
+
+ if (theEncoder.get()) {
+
+ utility::inputStreamStringAdapter in(theText->value);
+ utility::outputStreamStringAdapter out(value);
+
+ theEncoder->decode(in, out);
+
+ // No decoder available
+ } else {
+
+ value = theText->value;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ vmime::charset charset;
+ string value;
+ };
+
+
+ // seq-number = nz-number / "*"
+ // ; message sequence number (COPY, FETCH, STORE
+ // ; commands) or unique identifier (UID COPY,
+ // ; UID FETCH, UID STORE commands).
+
+ DECLARE_COMPONENT(seq_number)
+
+ seq_number()
+ : star(false) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'*'> )) {
+
+ star = true;
+ number.reset();
+
+ } else {
+
+ star = false;
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::number> number;
+ bool star;
+ };
+
+
+ // seq-range = seq-number ":" seq-number
+ // ; two seq-number values and all values between
+ // ; these two regardless of order.
+ // ; Example: 2:4 and 4:2 are equivalent and indicate
+ // ; values 2, 3, and 4.
+
+ DECLARE_COMPONENT(seq_range)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(seq_number, first);
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+
+ VIMAP_PARSER_GET(seq_number, last);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::seq_number> first;
+ std::unique_ptr <IMAPParser::seq_number> last;
+ };
+
+
+ // sequence-set = (seq-number / seq-range) *("," sequence-set)
+ // ; set of seq-number values, regardless of order.
+ // ; Servers MAY coalesce overlaps and/or execute the
+ // ; sequence in any order.
+ // ; Example: a message sequence number set of
+ // ; 2,4:7,9,12:* for a mailbox with 15 messages is
+ // ; equivalent to 2,4,5,6,7,9,12,13,14,15
+
+ DECLARE_COMPONENT(sequence_set)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::seq_range, range)) {
+ VIMAP_PARSER_GET(IMAPParser::seq_number, number);
+ }
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <','> )) {
+ VIMAP_PARSER_GET(sequence_set, nextSet);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::seq_number> number;
+ std::unique_ptr <IMAPParser::seq_range> range;
+ std::unique_ptr <IMAPParser::sequence_set> nextSet;
+ };
+
+
+ // mod-sequence-value = 1*DIGIT
+ // ;; Positive unsigned 64-bit integer
+ // ;; (mod-sequence)
+ // ;; (1 <= n < 18,446,744,073,709,551,615)
+
+ DECLARE_COMPONENT(mod_sequence_value)
+
+ mod_sequence_value()
+ : value(0) {
+
+ }
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ bool valid = true;
+ vmime_uint64 val = 0;
+
+ while (valid && pos < line.length()) {
+
+ const char c = line[pos];
+
+ if (c >= '0' && c <= '9') {
+ val = (val * 10) + (c - '0');
+ ++pos;
+ } else {
+ valid = false;
+ }
+ }
+
+ value = val;
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ vmime_uint64 value;
+ };
+
+
+ //
+ // flag ::= "\Answered" / "\Flagged" / "\Deleted" /
+ // "\Seen" / "\Draft" / flag_keyword / flag_extension
+ //
+ // flag_extension ::= "\" atom
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept flag_extension flags. Server
+ // ;; implementations MUST NOT generate
+ // ;; flag_extension flags except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+ // flag_keyword ::= atom
+ //
+
+ DECLARE_COMPONENT(flag)
+
+ flag()
+ : type(UNKNOWN) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'\\'> )) {
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'*'> )) {
+
+ type = STAR;
+
+ } else {
+
+ shared_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ const string tname = utility::stringUtils::toLower(at->value);
+
+ if (tname == "answered") {
+ type = ANSWERED;
+ } else if (tname == "flagged") {
+ type = FLAGGED;
+ } else if (tname == "deleted") {
+ type = DELETED;
+ } else if (tname == "seen") {
+ type = SEEN;
+ } else if (tname == "draft") {
+ type = DRAFT;
+ } else {
+ type = UNKNOWN;
+ name = tname;
+ }
+ }
+
+ } else {
+
+ if (!parser.isStrict() && VIMAP_PARSER_TRY_CHECK(one_char <'*'> )) {
+ type = STAR; // map "*" to "\*"
+ } else {
+ type = KEYWORD_OR_EXTENSION;
+ VIMAP_PARSER_GET(atom, flag_keyword);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ UNKNOWN,
+ ANSWERED,
+ FLAGGED,
+ DELETED,
+ SEEN,
+ DRAFT,
+ KEYWORD_OR_EXTENSION,
+ STAR // * = custom flags allowed
+ };
+
+
+ Type type;
+ string name;
+
+ std::unique_ptr <IMAPParser::atom> flag_keyword;
+ };
+
+
+ //
+ // flag_list ::= "(" #flag ")"
+ //
+
+ DECLARE_COMPONENT(flag_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(flag, flags);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <flag>> flags;
+ };
+
+
+ //
+ // mailbox ::= "INBOX" / astring
+ // ;; INBOX is case-insensitive. All case variants of
+ // ;; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
+ // ;; not as an astring. Refer to section 5.1 for
+ // ;; further semantic details of mailbox names.
+ //
+
+ DECLARE_COMPONENT(mailbox)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "inbox")) {
+
+ type = INBOX;
+ name = "INBOX";
+
+ } else {
+
+ type = OTHER;
+
+ std::unique_ptr <astring> astr;
+ VIMAP_PARSER_GET(astring, astr);
+ name = astr->value;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ INBOX,
+ OTHER
+ };
+
+
+ Type type;
+ string name;
+ };
+
+
+ //
+ // mailbox_flag := "\Marked" / "\Noinferiors" /
+ // "\Noselect" / "\Unmarked" / flag_extension
+ //
+
+ DECLARE_COMPONENT(mailbox_flag)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'\\'> )) {
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ const string tname = utility::stringUtils::toLower(at->value);
+
+ type = UNKNOWN; // default
+
+ switch (tname[0]) {
+
+ case 'a':
+
+ if (tname == "all") {
+ type = SPECIALUSE_ALL;
+ } else if (tname == "archive") {
+ type = SPECIALUSE_ARCHIVE;
+ }
+
+ break;
+
+ case 'd':
+
+ if (tname == "drafts") {
+ type = SPECIALUSE_DRAFTS;
+ }
+
+ break;
+
+ case 'f':
+
+ if (tname == "flagged") {
+ type = SPECIALUSE_FLAGGED;
+ }
+
+ break;
+
+ case 'h':
+
+ if (tname == "haschildren") {
+ type = HASCHILDREN;
+ } else if (tname == "hasnochildren") {
+ type = HASNOCHILDREN;
+ }
+
+ break;
+
+ case 'i':
+
+ if (tname == "important") {
+ type = SPECIALUSE_IMPORTANT;
+ }
+
+ break;
+
+ case 'j':
+
+ if (tname == "junk") {
+ type = SPECIALUSE_JUNK;
+ }
+
+ break;
+
+ case 'm':
+
+ if (tname == "marked") {
+ type = MARKED;
+ }
+
+ break;
+
+ case 'n':
+
+ if (tname == "noinferiors") {
+ type = NOINFERIORS;
+ } else if (tname == "noselect") {
+ type = NOSELECT;
+ }
+
+ break;
+
+ case 's':
+
+ if (tname == "sent") {
+ type = SPECIALUSE_SENT;
+ }
+
+ break;
+
+ case 't':
+
+ if (tname == "trash") {
+ type = SPECIALUSE_TRASH;
+ }
+
+ break;
+
+ case 'u':
+
+ if (tname == "unmarked") {
+ type = UNMARKED;
+ }
+
+ break;
+ }
+
+ if (type == UNKNOWN) {
+ name = "\\" + tname;
+ }
+
+ } else {
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+ const string tname = utility::stringUtils::toLower(at->value);
+
+ type = UNKNOWN;
+ name = tname;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ // RFC-3348 - Child Mailbox Extension
+ HASCHILDREN,
+ HASNOCHILDREN,
+
+ // RFC-6154 - Special-Use Mailboxes
+ SPECIALUSE_ALL,
+ SPECIALUSE_ARCHIVE,
+ SPECIALUSE_DRAFTS,
+ SPECIALUSE_FLAGGED,
+ SPECIALUSE_JUNK,
+ SPECIALUSE_SENT,
+ SPECIALUSE_TRASH,
+ SPECIALUSE_IMPORTANT, // draft
+
+ // Standard mailbox flags
+ UNKNOWN,
+ MARKED,
+ NOINFERIORS,
+ NOSELECT,
+ UNMARKED
+ };
+
+
+ Type type;
+ string name;
+ };
+
+
+ //
+ // mailbox_flag_list ::= "(" #(mailbox_flag) ")"
+ //
+
+ DECLARE_COMPONENT(mailbox_flag_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(mailbox_flag, flags);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <mailbox_flag>> flags;
+ };
+
+
+ //
+ // mailbox_list ::= mailbox_flag_list SPACE
+ // (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
+ //
+
+ DECLARE_COMPONENT(mailbox_list)
+
+ mailbox_list()
+ : quoted_char('\0') {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_flag_list, mailbox_flag_list);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!VIMAP_PARSER_TRY_CHECK(NIL)) {
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+
+ std::unique_ptr <QUOTED_CHAR> qc;
+ VIMAP_PARSER_GET(QUOTED_CHAR, qc);
+ quoted_char = qc->value;
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox, mailbox);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::mailbox_flag_list> mailbox_flag_list;
+ std::unique_ptr <IMAPParser::mailbox> mailbox;
+
+ char quoted_char;
+ };
+
+
+ //
+ // auth_type ::= atom
+ // ;; Defined by [IMAP-AUTH]
+ //
+
+ DECLARE_COMPONENT(auth_type)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ name = utility::stringUtils::toLower(at->value);
+
+ if (name == "kerberos_v4") {
+ type = KERBEROS_V4;
+ } else if (name == "gssapi") {
+ type = GSSAPI;
+ } else if (name == "skey") {
+ type = SKEY;
+ } else {
+ type = UNKNOWN;
+ }
+
+ return true;
+ }
+
+
+ enum Type {
+ UNKNOWN,
+
+ // RFC 1731 - IMAP4 Authentication Mechanisms
+ KERBEROS_V4,
+ GSSAPI,
+ SKEY
+ };
+
+
+ Type type;
+ string name;
+ };
+
+
+ //
+ // status-att-val = ("MESSAGES" SP number) /
+ // ("RECENT" SP number) /
+ // ("UIDNEXT" SP nz-number) /
+ // ("UIDVALIDITY" SP nz-number) /
+ // ("UNSEEN" SP number)
+ //
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // status-att-val =/ "HIGHESTMODSEQ" SP mod-sequence-valzer
+ // ;; extends non-terminal defined in [IMAPABNF].
+ // ;; Value 0 denotes that the mailbox doesn't
+ // ;; support persistent mod-sequences
+ //
+
+ DECLARE_COMPONENT(status_att_val)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "HIGHESTMODSEQ" SP mod-sequence-valzer
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "highestmodseq")) {
+
+ type = HIGHESTMODSEQ;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::mod_sequence_value, value);
+
+ } else {
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "messages")) {
+ type = MESSAGES;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "recent")) {
+ type = RECENT;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidnext")) {
+ type = UIDNEXT;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidvalidity")) {
+ type = UIDVALIDITY;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "unseen");
+ type = UNSEEN;
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::number, value);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ // Extensions
+ HIGHESTMODSEQ,
+
+ // Standard IMAP
+ MESSAGES,
+ RECENT,
+ UIDNEXT,
+ UIDVALIDITY,
+ UNSEEN
+ };
+
+
+ Type type;
+ std::unique_ptr <IMAPParser::component> value;
+
+
+ const IMAPParser::number* value_as_number() const {
+ return dynamic_cast <IMAPParser::number *>(value.get());
+ }
+
+ const IMAPParser::mod_sequence_value* value_as_mod_sequence_value() const {
+ return dynamic_cast <IMAPParser::mod_sequence_value *>(value.get());
+ }
+ };
+
+
+ // status-att-list = status-att-val *(SP status-att-val)
+
+ DECLARE_COMPONENT(status_att_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET_PUSHBACK(IMAPParser::status_att_val, values);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(IMAPParser::status_att_val, values);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <status_att_val>> values;
+ };
+
+
+ //
+ // capability ::= "AUTH=" auth_type / atom
+ // ;; New capabilities MUST begin with "X" or be
+ // ;; registered with IANA as standard or standards-track
+ //
+
+ DECLARE_COMPONENT(capability)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::atom, atom);
+
+ string value = atom->value;
+ const char* str = value.c_str();
+
+ if ((str[0] == 'a' || str[0] == 'A') &&
+ (str[1] == 'u' || str[1] == 'U') &&
+ (str[2] == 't' || str[2] == 'T') &&
+ (str[3] == 'h' || str[3] == 'H') &&
+ (str[4] == '=')) {
+
+ size_t pos = 5;
+ auth_type.reset(parser.get <IMAPParser::auth_type>(value, &pos));
+
+ atom.reset();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::auth_type> auth_type;
+ std::unique_ptr <IMAPParser::atom> atom;
+ };
+
+
+ //
+ // capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1"
+ // [SPACE 1#capability]
+ // ;; IMAP4rev1 servers which offer RFC 1730
+ // ;; compatibility MUST list "IMAP4" as the first
+ // ;; capability.
+ //
+
+ DECLARE_COMPONENT(capability_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "capability");
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ std::unique_ptr <capability> cap;
+
+ if (parser.isStrict() || capabilities.empty()) {
+ VIMAP_PARSER_GET(capability, cap);
+ } else {
+ VIMAP_PARSER_TRY_GET(capability, cap); // allow SPACE at end of line (Apple iCloud IMAP server)
+ }
+
+ if (!cap) {
+ break;
+ }
+
+ capabilities.push_back(std::move(cap));
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <capability>> capabilities;
+ };
+
+
+ //
+ // date_day_fixed ::= (SPACE digit) / 2digit
+ // ;; Fixed-format version of date_day
+ //
+ // date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ // "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+ //
+ // date_year ::= 4digit
+ //
+ // time ::= 2digit ":" 2digit ":" 2digit
+ // ;; Hours minutes seconds
+ //
+ // zone ::= ("+" / "-") 4digit
+ // ;; Signed four-digit value of hhmm representing
+ // ;; hours and minutes west of Greenwich (that is,
+ // ;; (the amount that the given time differs from
+ // ;; Universal Time). Subtracting the timezone
+ // ;; from the given time will give the UT form.
+ // ;; The Universal Time zone is "+0000".
+ //
+ // date_time ::= <"> date_day_fixed "-" date_month "-" date_year
+ // SPACE time SPACE zone <">
+ //
+
+ DECLARE_COMPONENT(date_time)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // <"> date_day_fixed "-" date_month "-" date_year
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ shared_ptr <number> nd;
+ VIMAP_PARSER_GET(number, nd);
+
+ VIMAP_PARSER_CHECK(one_char <'-'> );
+
+ shared_ptr <atom> amo;
+ VIMAP_PARSER_GET(atom, amo);
+
+ VIMAP_PARSER_CHECK(one_char <'-'> );
+
+ shared_ptr <number> ny;
+ VIMAP_PARSER_GET(number, ny);
+
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ // 2digit ":" 2digit ":" 2digit
+ shared_ptr <number> nh;
+ VIMAP_PARSER_GET(number, nh);
+
+ VIMAP_PARSER_CHECK(one_char <':'> );
+
+ shared_ptr <number> nmi;
+ VIMAP_PARSER_GET(number, nmi);
+
+ VIMAP_PARSER_CHECK(one_char <':'> );
+
+ shared_ptr <number> ns;
+ VIMAP_PARSER_GET(number, ns);
+
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ // ("+" / "-") 4digit
+ int sign = 1;
+
+ if (!(VIMAP_PARSER_TRY_CHECK(one_char <'+'> ))) {
+ VIMAP_PARSER_CHECK(one_char <'-'> );
+ }
+
+ shared_ptr <number> nz;
+ VIMAP_PARSER_GET(number, nz);
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+
+
+ m_datetime.setHour(static_cast <int>(std::min(std::max(nh->value, 0ul), 23ul)));
+ m_datetime.setMinute(static_cast <int>(std::min(std::max(nmi->value, 0ul), 59ul)));
+ m_datetime.setSecond(static_cast <int>(std::min(std::max(ns->value, 0ul), 59ul)));
+
+ const int zone = static_cast <int>(nz->value);
+ const int zh = zone / 100; // hour offset
+ const int zm = zone % 100; // minute offset
+
+ m_datetime.setZone(((zh * 60) + zm) * sign);
+
+ m_datetime.setDay(static_cast <int>(std::min(std::max(nd->value, 1ul), 31ul)));
+ m_datetime.setYear(static_cast <int>(ny->value));
+
+ const string month(utility::stringUtils::toLower(amo->value));
+ int mon = vmime::datetime::JANUARY;
+
+ if (month.length() >= 3) {
+
+ switch (month[0]) {
+
+ case 'j': {
+
+ switch (month[1]) {
+
+ case 'a': mon = vmime::datetime::JANUARY; break;
+ case 'u': {
+
+ switch (month[2]) {
+
+ case 'n': mon = vmime::datetime::JUNE; break;
+ default: mon = vmime::datetime::JULY; break;
+ }
+
+ break;
+ }
+
+ }
+
+ break;
+ }
+ case 'f': mon = vmime::datetime::FEBRUARY; break;
+ case 'm': {
+
+ switch (month[2]) {
+ case 'r': mon = vmime::datetime::MARCH; break;
+ default: mon = vmime::datetime::MAY; break;
+ }
+
+ break;
+ }
+ case 'a':
+ {
+ switch (month[1]) {
+ case 'p': mon = vmime::datetime::APRIL; break;
+ default: mon = vmime::datetime::AUGUST; break;
+ }
+
+ break;
+ }
+ case 's': mon = vmime::datetime::SEPTEMBER; break;
+ case 'o': mon = vmime::datetime::OCTOBER; break;
+ case 'n': mon = vmime::datetime::NOVEMBER; break;
+ case 'd': mon = vmime::datetime::DECEMBER; break;
+ }
+ }
+
+ m_datetime.setMonth(mon);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ private:
+
+ vmime::datetime m_datetime;
+ };
+
+
+ //
+ // header_fld_name ::= astring
+ //
+
+ COMPONENT_ALIAS(astring, header_fld_name);
+
+
+ //
+ // header_list ::= "(" 1#header_fld_name ")"
+ //
+
+ DECLARE_COMPONENT(header_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(header_fld_name, fld_names);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <header_fld_name>> fld_names;
+ };
+
+
+ //
+ // body_extension ::= nstring / number / "(" 1#body_extension ")"
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept body_extension fields. Server
+ // ;; implementations MUST NOT generate
+ // ;; body_extension fields except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+
+ DECLARE_COMPONENT(body_extension)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ } else {
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::nstring, nstring)) {
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::nstring> nstring;
+ std::unique_ptr <IMAPParser::number> number;
+
+ std::vector <std::unique_ptr <body_extension>> body_extensions;
+ };
+
+
+ //
+ // section_text ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
+ // SPACE header_list / "TEXT" / "MIME"
+ //
+
+ DECLARE_COMPONENT(section_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "HEADER.FIELDS" [".NOT"] SPACE header_list
+ const bool b1 = VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "header.fields.not");
+ const bool b2 = (b1 ? false : VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "header.fields"));
+
+ if (b1 || b2) {
+
+ type = b1 ? HEADER_FIELDS_NOT : HEADER_FIELDS;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::header_list, header_list);
+
+ // "HEADER"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "header")) {
+
+ type = HEADER;
+
+ // "MIME"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "mime")) {
+
+ type = MIME;
+
+ // "TEXT"
+ } else {
+
+ type = TEXT;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "text");
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ HEADER,
+ HEADER_FIELDS,
+ HEADER_FIELDS_NOT,
+ MIME,
+ TEXT
+ };
+
+
+ Type type;
+ std::unique_ptr <IMAPParser::header_list> header_list;
+ };
+
+
+ //
+ // section ::= "[" [section_text / (nz_number *["." nz_number]
+ // ["." (section_text / "MIME")])] "]"
+ //
+
+ DECLARE_COMPONENT(section)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'['> );
+
+ if (!VIMAP_PARSER_TRY_CHECK(one_char <']'> )) {
+
+ if (!VIMAP_PARSER_TRY_GET(section_text, section_text1)) {
+
+ std::unique_ptr <nz_number> num;
+ VIMAP_PARSER_GET(nz_number, num);
+ nz_numbers.push_back(static_cast <unsigned int>(num->value));
+
+ while (VIMAP_PARSER_TRY_CHECK(one_char <'.'> )) {
+
+ if (VIMAP_PARSER_TRY_GET(nz_number, num)) {
+ nz_numbers.push_back(static_cast <unsigned int>(num->value));
+ } else {
+ VIMAP_PARSER_GET(section_text, section_text2);
+ break;
+ }
+ }
+ }
+
+ VIMAP_PARSER_CHECK(one_char <']'> );
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <section_text> section_text1;
+ std::unique_ptr <section_text> section_text2;
+ std::vector <unsigned int> nz_numbers;
+ };
+
+
+ //
+ // addr_adl ::= nstring
+ // ;; Holds route from [RFC-822] route-addr if
+ // ;; non-NIL
+ //
+ // addr_host ::= nstring
+ // ;; NIL indicates [RFC-822] group syntax.
+ // ;; Otherwise, holds [RFC-822] domain name
+ //
+ // addr_mailbox ::= nstring
+ // ;; NIL indicates end of [RFC-822] group; if
+ // ;; non-NIL and addr_host is NIL, holds
+ // ;; [RFC-822] group name.
+ // ;; Otherwise, holds [RFC-822] local-part
+ //
+ // addr_name ::= nstring
+ // ;; Holds phrase from [RFC-822] mailbox if
+ // ;; non-NIL
+ //
+ // address ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
+ // SPACE addr_host ")"
+ //
+
+ DECLARE_COMPONENT(address)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+ VIMAP_PARSER_GET(nstring, addr_name);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(nstring, addr_adl);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(nstring, addr_mailbox);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(nstring, addr_host);
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <nstring> addr_name;
+ std::unique_ptr <nstring> addr_adl;
+ std::unique_ptr <nstring> addr_mailbox;
+ std::unique_ptr <nstring> addr_host;
+ };
+
+
+ //
+ // address_list ::= "(" 1*address ")" / nil
+ //
+
+ DECLARE_COMPONENT(address_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_CHECK(NIL)) {
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(address, addresses);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <address>> addresses;
+ };
+
+
+ //
+ // env_bcc ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_bcc);
+
+
+ //
+ // env_cc ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_cc);
+
+
+ //
+ // env_date ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_date);
+
+
+ //
+ // env_from ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_from);
+
+
+ //
+ // env_in_reply_to ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_in_reply_to);
+
+
+ //
+ // env_message_id ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_message_id);
+
+
+ //
+ // env_reply_to ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_reply_to);
+
+
+ //
+ // env_sender ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_sender);
+
+
+ //
+ // env_subject ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_subject);
+
+
+ //
+ // env_to ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_to);
+
+
+ //
+ // envelope ::= "(" env_date SPACE env_subject SPACE env_from
+ // SPACE env_sender SPACE env_reply_to SPACE env_to
+ // SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
+ // SPACE env_message_id ")"
+ //
+
+ DECLARE_COMPONENT(envelope)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ VIMAP_PARSER_GET(IMAPParser::env_date, env_date);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_subject, env_subject);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_from, env_from);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_sender, env_sender);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_reply_to, env_reply_to);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_to, env_to);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_cc, env_cc);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_bcc, env_bcc);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_in_reply_to, env_in_reply_to);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_message_id, env_message_id);
+
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::env_date> env_date;
+ std::unique_ptr <IMAPParser::env_subject> env_subject;
+ std::unique_ptr <IMAPParser::env_from> env_from;
+ std::unique_ptr <IMAPParser::env_sender> env_sender;
+ std::unique_ptr <IMAPParser::env_reply_to> env_reply_to;
+ std::unique_ptr <IMAPParser::env_to> env_to;
+ std::unique_ptr <IMAPParser::env_cc> env_cc;
+ std::unique_ptr <IMAPParser::env_bcc> env_bcc;
+ std::unique_ptr <IMAPParser::env_in_reply_to> env_in_reply_to;
+ std::unique_ptr <IMAPParser::env_message_id> env_message_id;
+ };
+
+
+ //
+ // body_fld_desc ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, body_fld_desc);
+
+
+ //
+ // body_fld_id ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, body_fld_id);
+
+
+ //
+ // body_fld_md5 ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, body_fld_md5);
+
+
+ //
+ // body_fld_octets ::= number
+ //
+
+ COMPONENT_ALIAS(number, body_fld_octets);
+
+
+ //
+ // body_fld_lines ::= number
+ //
+
+ COMPONENT_ALIAS(number, body_fld_lines);
+
+
+ //
+ // body_fld_enc ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+ // "QUOTED-PRINTABLE") <">) / string
+ //
+
+ class body_fld_enc : public nstring {
+
+ public:
+
+ const string getComponentName() const {
+
+ return "body_fld_enc";
+ }
+
+ body_fld_enc() {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!xstring::parseImpl(parser, line, &pos)) {
+ return false;
+ }
+
+ // " When an IMAP4 client sends a FETCH (bodystructure) request
+ // to a server that is running the Exchange Server 2007 IMAP4
+ // service, a corrupted response is sent as a reply "
+ // (see http://support.microsoft.com/kb/975918/en-us)
+ //
+ // Fail in strict mode
+ if (isNIL && parser.isStrict()) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+ };
+
+
+ //
+ // body_fld_param_item ::= string SPACE string
+ //
+
+ DECLARE_COMPONENT(body_fld_param_item)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!parser.isStrict()) {
+
+ // Some servers send an <atom> instead of a <string> here:
+ // eg. ... (CHARSET "X-UNKNOWN") ...
+ if (!VIMAP_PARSER_TRY_GET(xstring, string1)) {
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ string1.reset(new xstring());
+ string1->value = at->value;
+ }
+
+ } else {
+
+ VIMAP_PARSER_GET(xstring, string1);
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!parser.isStrict()) {
+
+ // In non-strict mode, allow NIL in value
+ std::unique_ptr <nstring> nstr;
+ VIMAP_PARSER_GET(nstring, nstr);
+
+ string2.reset(new xstring());
+ string2->value = nstr->value;
+
+ } else {
+
+ VIMAP_PARSER_GET(xstring, string2);
+ }
+
+ DEBUG_FOUND("body_fld_param_item", "<" << string1->value << ", " << string2->value << ">");
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <xstring> string1;
+ std::unique_ptr <xstring> string2;
+ };
+
+
+ //
+ // body_fld_param ::= "(" 1#(body_fld_param_item) ")" / nil
+ //
+
+ DECLARE_COMPONENT(body_fld_param)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ bool isNIL = false;
+
+ if (!parser.isStrict()) {
+
+ // In non-strict mode, allow "()" instead of "NIL"
+ if (VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ isNIL = true;
+ }
+ }
+
+ if (!isNIL) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_fld_param_item, items);
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET_PUSHBACK(body_fld_param_item, items);
+ }
+ }
+
+ } else {
+
+ VIMAP_PARSER_CHECK(NIL);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <body_fld_param_item>> items;
+ };
+
+
+ //
+ // body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil
+ //
+
+ DECLARE_COMPONENT(body_fld_dsp)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ VIMAP_PARSER_GET(xstring, m_string);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(class body_fld_param, m_body_fld_param);
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ } else {
+
+ VIMAP_PARSER_CHECK(NIL);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ private:
+
+ std::unique_ptr <class xstring> m_string;
+ std::unique_ptr <class body_fld_param> m_body_fld_param;
+
+ public:
+
+ const class xstring* str() const { return m_string.get(); }
+ const class body_fld_param* body_fld_param() const { return m_body_fld_param.get(); }
+ };
+
+
+ //
+ // body_fld_lang ::= nstring / "(" 1#string ")"
+ //
+
+ DECLARE_COMPONENT(body_fld_lang)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ VIMAP_PARSER_GET_PUSHBACK(xstring, strings);
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET_PUSHBACK(xstring, strings);
+ }
+
+ } else {
+
+ VIMAP_PARSER_GET_PUSHBACK(nstring, strings);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <xstring>> strings;
+ };
+
+
+ //
+ // body_fields ::= body_fld_param SPACE body_fld_id SPACE
+ // body_fld_desc SPACE body_fld_enc SPACE
+ // body_fld_octets
+ //
+
+ DECLARE_COMPONENT(body_fields)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_param, body_fld_param);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_id, body_fld_id);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_desc, body_fld_desc);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_enc, body_fld_enc);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_octets, body_fld_octets);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_fld_param> body_fld_param;
+ std::unique_ptr <IMAPParser::body_fld_id> body_fld_id;
+ std::unique_ptr <IMAPParser::body_fld_desc> body_fld_desc;
+ std::unique_ptr <IMAPParser::body_fld_enc> body_fld_enc;
+ std::unique_ptr <IMAPParser::body_fld_octets> body_fld_octets;
+ };
+
+
+ //
+ // media_subtype ::= string
+ // ;; Defined in [MIME-IMT]
+ //
+
+ COMPONENT_ALIAS(xstring, media_subtype);
+
+
+ //
+ // media_text ::= <"> "TEXT" <"> SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+ //
+
+ DECLARE_COMPONENT(media_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "text");
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ };
+
+
+ //
+ // media_message ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <">
+ // ;; Defined in [MIME-IMT]
+ //
+
+ DECLARE_COMPONENT(media_message)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "message");
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ //VIMAP_PARSER_CHECK(one_char <'"'> );
+ //VIMAP_PARSER_CHECK_WITHARG(special_atom, "rfc822");
+ //VIMAP_PARSER_CHECK(one_char <'"'> );
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ };
+
+
+ //
+ // media_basic ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" /
+ // "MESSAGE" / "VIDEO") <">) / string)
+ // SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+
+ DECLARE_COMPONENT(media_basic)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(xstring, media_type);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::xstring> media_type;
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ };
+
+
+ //
+ // body_ext_1part ::= body_fld_md5 [SPACE body_fld_dsp
+ // [SPACE body_fld_lang
+ // [SPACE 1#body_extension]]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+ //
+
+ DECLARE_COMPONENT(body_ext_1part)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos)
+ {
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_md5, body_fld_md5);
+
+ // [SPACE body_fld_dsp
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_dsp, body_fld_dsp);
+
+ // [SPACE body_fld_lang
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lang, body_fld_lang);
+
+ // [SPACE 1#body_extension]
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+ }
+ }
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_fld_md5> body_fld_md5;
+ std::unique_ptr <IMAPParser::body_fld_dsp> body_fld_dsp;
+ std::unique_ptr <IMAPParser::body_fld_lang> body_fld_lang;
+
+ std::vector <std::unique_ptr <body_extension>> body_extensions;
+ };
+
+
+ //
+ // body_ext_mpart ::= body_fld_param
+ // [SPACE body_fld_dsp [SPACE body_fld_lang
+ // [SPACE 1#body_extension]]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+
+ DECLARE_COMPONENT(body_ext_mpart)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_param, body_fld_param);
+
+ // [SPACE body_fld_dsp [SPACE body_fld_lang [SPACE 1#body_extension]]]
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_dsp, body_fld_dsp);
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lang, body_fld_lang);
+
+ // [SPACE 1#body_extension]
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+ }
+ }
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_fld_param> body_fld_param;
+ std::unique_ptr <IMAPParser::body_fld_dsp> body_fld_dsp;
+ std::unique_ptr <IMAPParser::body_fld_lang> body_fld_lang;
+
+ std::vector <std::unique_ptr <body_extension>> body_extensions;
+ };
+
+
+ //
+ // body_type_basic ::= media_basic SPACE body_fields
+ // ;; MESSAGE subtype MUST NOT be "RFC822"
+ //
+
+ DECLARE_COMPONENT(body_type_basic)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::media_basic, media_basic);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fields, body_fields);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_basic> media_basic;
+ std::unique_ptr <IMAPParser::body_fields> body_fields;
+ };
+
+
+ //
+ // body_type_msg ::= media_message SPACE body_fields SPACE envelope
+ // SPACE body SPACE body_fld_lines
+ //
+
+ class xbody;
+ typedef xbody body;
+
+ DECLARE_COMPONENT(body_type_msg)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::media_message, media_message);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fields, body_fields);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ // BUGFIX: made SPACE optional. This is not standard, but some servers
+ // seem to return responses like that...
+ VIMAP_PARSER_GET(IMAPParser::envelope, envelope);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::xbody, body);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lines, body_fld_lines);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_message> media_message;
+ std::unique_ptr <IMAPParser::body_fields> body_fields;
+ std::unique_ptr <IMAPParser::envelope> envelope;
+ std::unique_ptr <IMAPParser::xbody> body;
+ std::unique_ptr <IMAPParser::body_fld_lines> body_fld_lines;
+ };
+
+
+ //
+ // body_type_text ::= media_text SPACE body_fields SPACE body_fld_lines
+ //
+
+ DECLARE_COMPONENT(body_type_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::media_text, media_text);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fields, body_fields);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lines, body_fld_lines);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_text> media_text;
+ std::unique_ptr <IMAPParser::body_fields> body_fields;
+ std::unique_ptr <IMAPParser::body_fld_lines> body_fld_lines;
+ };
+
+
+ //
+ // body_type_1part ::= (body_type_basic / body_type_msg / body_type_text)
+ // [SPACE body_ext_1part]
+ //
+
+ DECLARE_COMPONENT(body_type_1part)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_type_text, body_type_text)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_type_msg, body_type_msg)) {
+ VIMAP_PARSER_GET(IMAPParser::body_type_basic, body_type_basic);
+ }
+ }
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_ext_1part, body_ext_1part)) {
+ --pos;
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_type_basic> body_type_basic;
+ std::unique_ptr <IMAPParser::body_type_msg> body_type_msg;
+ std::unique_ptr <IMAPParser::body_type_text> body_type_text;
+
+ std::unique_ptr <IMAPParser::body_ext_1part> body_ext_1part;
+ };
+
+
+ //
+ // body_type_mpart ::= 1*body SPACE media_subtype
+ // [SPACE body_ext_mpart]
+ //
+
+ DECLARE_COMPONENT(body_type_mpart)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET_PUSHBACK(xbody, list);
+
+ while (true) {
+ VIMAP_PARSER_TRY_GET_PUSHBACK_OR_ELSE(xbody, list, break);
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET(IMAPParser::body_ext_mpart, body_ext_mpart);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ std::unique_ptr <IMAPParser::body_ext_mpart> body_ext_mpart;
+
+ std::vector <std::unique_ptr <xbody>> list;
+ };
+
+
+ //
+ // xbody ::= "(" body_type_1part / body_type_mpart ")"
+ //
+
+ DECLARE_COMPONENT(xbody)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_type_mpart, body_type_mpart)) {
+ VIMAP_PARSER_GET(IMAPParser::body_type_1part, body_type_1part);
+ }
+
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_type_1part> body_type_1part;
+ std::unique_ptr <IMAPParser::body_type_mpart> body_type_mpart;
+ };
+
+
+ // msg_att_item ::= "ENVELOPE" SPACE envelope /
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")" /
+ // "INTERNALDATE" SPACE date_time /
+ // "RFC822" [".HEADER" / ".TEXT"] SPACE nstring /
+ // "RFC822.SIZE" SPACE number /
+ // "BODY" ["STRUCTURE"] SPACE body /
+ // "BODY" section ["<" number ">"] SPACE nstring /
+ // "UID" SPACE uniqueid
+ //
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // msg_att_item /= "MODSEQ" SP "(" mod_sequence_value ")"
+
+ DECLARE_COMPONENT(msg_att_item)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "ENVELOPE" SPACE envelope
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "envelope")) {
+
+ type = ENVELOPE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::envelope, envelope);
+
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "flags")) {
+
+ type = FLAGS;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::flag_list, flag_list);
+
+ // "INTERNALDATE" SPACE date_time
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "internaldate")) {
+
+ type = INTERNALDATE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::date_time, date_time);
+
+ // "RFC822" ".HEADER" SPACE nstring
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822.header")) {
+
+ type = RFC822_HEADER;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::nstring, nstring);
+
+ // "RFC822" ".TEXT" SPACE nstring
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822.text")) {
+
+ type = RFC822_TEXT;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ nstring.reset(parser.getWithArgs <IMAPParser::nstring>(line, &pos, this, RFC822_TEXT));
+
+ VIMAP_PARSER_FAIL_UNLESS(nstring);
+
+ // "RFC822.SIZE" SPACE number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822.size")) {
+
+ type = RFC822_SIZE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+
+ // "RFC822" SPACE nstring
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822")) {
+
+ type = RFC822;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::nstring, nstring);
+
+ // "BODY" "STRUCTURE" SPACE body
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "bodystructure")) {
+
+ type = BODY_STRUCTURE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::body, body);
+
+ // "BODY" section ["<" number ">"] SPACE nstring
+ // "BODY" SPACE body
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "body")) {
+
+ VIMAP_PARSER_TRY_GET(IMAPParser::section, section);
+
+ // "BODY" section ["<" number ">"] SPACE nstring
+ if (section != NULL) {
+
+ type = BODY_SECTION;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'<'> )) {
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+ VIMAP_PARSER_CHECK(one_char <'>'> );
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ nstring.reset(parser.getWithArgs <IMAPParser::nstring>(line, &pos, this, BODY_SECTION));
+
+ VIMAP_PARSER_FAIL_UNLESS(nstring);
+
+ // "BODY" SPACE body
+ } else {
+
+ type = BODY;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::body, body);
+ }
+
+ // "MODSEQ" SP "(" mod_sequence_value ")"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "modseq")) {
+
+ type = MODSEQ;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ VIMAP_PARSER_GET(IMAPParser::mod_sequence_value, mod_sequence_value);
+
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ // "UID" SPACE uniqueid
+ } else {
+
+ type = UID;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "uid");
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::uniqueid, uniqueid);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ ENVELOPE,
+ FLAGS,
+ INTERNALDATE,
+ RFC822,
+ RFC822_SIZE,
+ RFC822_HEADER,
+ RFC822_TEXT,
+ BODY,
+ BODY_SECTION,
+ BODY_STRUCTURE,
+ UID,
+ MODSEQ
+ };
+
+
+ Type type;
+
+ std::unique_ptr <IMAPParser::date_time> date_time;
+ std::unique_ptr <IMAPParser::number> number;
+ std::unique_ptr <IMAPParser::envelope> envelope;
+ std::unique_ptr <IMAPParser::uniqueid> uniqueid;
+ std::unique_ptr <IMAPParser::nstring> nstring;
+ std::unique_ptr <IMAPParser::xbody> body;
+ std::unique_ptr <IMAPParser::flag_list> flag_list;
+ std::unique_ptr <IMAPParser::section> section;
+ std::unique_ptr <IMAPParser::mod_sequence_value> mod_sequence_value;
+ };
+
+
+ //
+ // msg_att ::= "(" 1#(msg_att_item) ")"
+ //
+
+ DECLARE_COMPONENT(msg_att)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ items.push_back(std::move(std::unique_ptr <msg_att_item>(parser.get <msg_att_item>(line, &pos))));
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET_PUSHBACK(msg_att_item, items);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <msg_att_item>> items;
+ };
+
+
+ //
+ // message_data ::= nz_number SPACE ("EXPUNGE" /
+ // ("FETCH" SPACE msg_att))
+ //
+
+ DECLARE_COMPONENT(message_data)
+
+ message_data()
+ : number(0) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ scoped_ptr <nz_number> num;
+ VIMAP_PARSER_GET(nz_number, num);
+ number = static_cast <unsigned int>(num->value);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "expunge")) {
+
+ type = EXPUNGE;
+
+ } else {
+
+ type = FETCH;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "fetch");
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::msg_att, msg_att);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ EXPUNGE,
+ FETCH
+ };
+
+
+ Type type;
+ unsigned int number;
+ std::unique_ptr <IMAPParser::msg_att> msg_att;
+ };
+
+
+ //
+ // resp_text_code ::= "ALERT" / "PARSE" /
+ // capability-data /
+ // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
+ // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+ // "UIDVALIDITY" SPACE nz_number /
+ // "UNSEEN" SPACE nz_number /
+ // "UIDNEXT" SPACE nz-number /
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ //
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // resp-text-code =/ "HIGHESTMODSEQ" SP mod-sequence-value /
+ // "NOMODSEQ" /
+ // "MODIFIED" SP set
+ //
+ // IMAP UIDPLUS Extension (RFC-4315):
+ //
+ // resp-text-code =/ "APPENDUID" SP nz-number SP append-uid /
+ // "COPYUID" SP nz-number SP uid-set SP uid-set /
+ // "UIDNOTSTICKY"
+
+ DECLARE_COMPONENT(resp_text_code)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "ALERT"
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "alert")) {
+
+ type = ALERT;
+
+ // "PARSE"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "parse")) {
+
+ type = PARSE;
+
+ // capability_data
+ } else if (VIMAP_PARSER_TRY_GET(IMAPParser::capability_data, capability_data)) {
+
+ type = CAPABILITY;
+
+ // "PERMANENTFLAGS" SPACE flag_list
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "permanentflags")) {
+
+ type = PERMANENTFLAGS;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::flag_list, flag_list);
+
+ // "READ-ONLY"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "read-only")) {
+
+ type = READ_ONLY;
+
+ // "READ-WRITE"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "read-write")) {
+
+ type = READ_WRITE;
+
+ // "TRYCREATE"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "trycreate")) {
+
+ type = TRYCREATE;
+
+ // "UIDVALIDITY" SPACE nz_number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidvalidity")) {
+
+ type = UIDVALIDITY;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+
+ // "UIDNEXT" SPACE nz_number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidnext")) {
+
+ type = UIDNEXT;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+
+ // "UNSEEN" SPACE nz_number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "unseen")) {
+
+ type = UNSEEN;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+
+ // "HIGHESTMODSEQ" SP mod-sequence-value
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "highestmodseq")) {
+
+ type = HIGHESTMODSEQ;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::mod_sequence_value, mod_sequence_value);
+
+ // "NOMODSEQ"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "nomodseq")) {
+
+ type = NOMODSEQ;
+
+ // "MODIFIED" SP sequence-set
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "modified")) {
+
+ type = MODIFIED;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::sequence_set, sequence_set);
+
+ // "APPENDUID" SP nz-number SP append-uid
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "appenduid")) {
+
+ type = APPENDUID;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::uid_set, uid_set);
+
+ // "COPYUID" SP nz-number SP uid-set SP uid-set
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "copyuid")) {
+
+ type = COPYUID;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::uid_set, uid_set);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::uid_set, uid_set2);
+
+ // "UIDNOTSTICKY"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidnotsticky")) {
+
+ type = UIDNOTSTICKY;
+
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ } else {
+
+ type = OTHER;
+
+ VIMAP_PARSER_GET(IMAPParser::atom, atom);
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET(text_except <']'> , text);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ // Extensions
+ HIGHESTMODSEQ,
+ NOMODSEQ,
+ MODIFIED,
+ APPENDUID,
+ COPYUID,
+ UIDNOTSTICKY,
+
+ // Standard IMAP
+ ALERT,
+ PARSE,
+ CAPABILITY,
+ PERMANENTFLAGS,
+ READ_ONLY,
+ READ_WRITE,
+ TRYCREATE,
+ UIDVALIDITY,
+ UIDNEXT,
+ UNSEEN,
+ OTHER
+ };
+
+
+ Type type;
+
+ std::unique_ptr <IMAPParser::nz_number> nz_number;
+ std::unique_ptr <IMAPParser::atom> atom;
+ std::unique_ptr <IMAPParser::flag_list> flag_list;
+ std::unique_ptr <IMAPParser::text> text;
+ std::unique_ptr <IMAPParser::mod_sequence_value> mod_sequence_value;
+ std::unique_ptr <IMAPParser::sequence_set> sequence_set;
+ std::unique_ptr <IMAPParser::capability_data> capability_data;
+ std::unique_ptr <IMAPParser::uid_set> uid_set;
+ std::unique_ptr <IMAPParser::uid_set> uid_set2;
+ };
+
+
+ //
+ // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
+ // ;; text SHOULD NOT begin with "[" or "="
+
+ DECLARE_COMPONENT(resp_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'['> )) {
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text_code, resp_text_code);
+
+ VIMAP_PARSER_CHECK(one_char <']'> );
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ std::unique_ptr <text_mime2> text1;
+ VIMAP_PARSER_TRY_GET(text_mime2, text1);
+
+ if (text1.get()) {
+
+ text = text1->value;
+
+ } else {
+
+ std::unique_ptr <IMAPParser::text> text2;
+ VIMAP_PARSER_TRY_GET(IMAPParser::text, text2);
+
+ if (text2.get()) {
+ text = text2->value;
+ } else {
+ // Empty response text
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_text_code> resp_text_code;
+ string text;
+ };
+
+
+ //
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+
+ DECLARE_COMPONENT(continue_req)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'+'> );
+
+ if (!parser.isStrict()) {
+
+ // Some servers do not send SPACE when response text is empty
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+ } else {
+ resp_text.reset(new IMAPParser::resp_text()); // empty
+ }
+
+ } else {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ };
+
+
+ //
+ // resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
+ // ;; Status condition
+ //
+
+ DECLARE_COMPONENT(resp_cond_state)
+
+ resp_cond_state()
+ : status(BAD) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "ok")) {
+ status = OK;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "no")) {
+ status = NO;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "bad");
+ status = BAD;
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Status {
+ OK,
+ NO,
+ BAD
+ };
+
+
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ Status status;
+ };
+
+
+ //
+ // resp_cond_bye ::= "BYE" SPACE resp_text
+ //
+
+ DECLARE_COMPONENT(resp_cond_bye)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "bye");
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ };
+
+
+ //
+ // resp_cond_auth ::= ("OK" / "PREAUTH") SPACE resp_text
+ // ;; Authentication condition
+ //
+
+ DECLARE_COMPONENT(resp_cond_auth)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "ok")) {
+ condition = OK;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "preauth");
+ condition = PREAUTH;
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Condition {
+ OK,
+ PREAUTH
+ };
+
+
+ Condition condition;
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ };
+
+
+ //
+ // mailbox_data ::= "FLAGS" SPACE mailbox_flag_list /
+ // "LIST" SPACE mailbox_list /
+ // "LSUB" SPACE mailbox_list /
+ // "MAILBOX" SPACE text /
+ // "SEARCH" [SPACE 1#nz_number] /
+ // "STATUS" SPACE mailbox SPACE
+ // "(" [status-att-list] ")" /
+ // number SPACE "EXISTS" /
+ // number SPACE "RECENT"
+ //
+
+ DECLARE_COMPONENT(mailbox_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_GET(IMAPParser::number, number)) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "exists")) {
+ type = EXISTS;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "recent");
+ type = RECENT;
+ }
+
+ } else {
+
+ // "FLAGS" SPACE mailbox_flag_list
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "flags")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_flag_list, mailbox_flag_list);
+
+ type = FLAGS;
+
+ // "LIST" SPACE mailbox_list
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "list")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_list, mailbox_list);
+
+ type = LIST;
+
+ // "LSUB" SPACE mailbox_list
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "lsub")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_list, mailbox_list);
+
+ type = LSUB;
+
+ // "MAILBOX" SPACE text
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "mailbox")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::text, text);
+
+ type = MAILBOX;
+
+ // "SEARCH" [SPACE 1#nz_number]
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "search")) {
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET_PUSHBACK(nz_number, search_nz_number_list);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(nz_number, search_nz_number_list);
+ }
+ }
+
+ type = SEARCH;
+
+ // "STATUS" SPACE mailbox SPACE
+ // "(" [status_att_list] ")"
+ } else {
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "status");
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox, mailbox);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+ VIMAP_PARSER_TRY_GET(IMAPParser::status_att_list, status_att_list);
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ type = STATUS;
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+
+ FLAGS,
+ LIST,
+ LSUB,
+ MAILBOX,
+ SEARCH,
+ STATUS,
+ EXISTS,
+ RECENT
+ };
+
+
+ Type type;
+
+ std::unique_ptr <IMAPParser::number> number;
+ std::unique_ptr <IMAPParser::mailbox_flag_list> mailbox_flag_list;
+ std::unique_ptr <IMAPParser::mailbox_list> mailbox_list;
+ std::unique_ptr <IMAPParser::mailbox> mailbox;
+ std::unique_ptr <IMAPParser::text> text;
+ std::vector <std::unique_ptr <nz_number>> search_nz_number_list;
+ std::unique_ptr <IMAPParser::status_att_list> status_att_list;
+ };
+
+
+ //
+ // response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
+ // mailbox_data / message_data / capability_data) CRLF
+ //
+
+ DECLARE_COMPONENT(response_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::resp_cond_state, resp_cond_state)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::resp_cond_bye, resp_cond_bye)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::mailbox_data, mailbox_data)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::message_data, message_data)) {
+ VIMAP_PARSER_GET(IMAPParser::capability_data, capability_data);
+ }
+ }
+ }
+ }
+
+ if (!parser.isStrict()) {
+
+ // Allow SPACEs at end of line
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ ;
+ }
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_cond_state> resp_cond_state;
+ std::unique_ptr <IMAPParser::resp_cond_bye> resp_cond_bye;
+ std::unique_ptr <IMAPParser::mailbox_data> mailbox_data;
+ std::unique_ptr <IMAPParser::message_data> message_data;
+ std::unique_ptr <IMAPParser::capability_data> capability_data;
+ };
+
+
+ DECLARE_COMPONENT(continue_req_or_response_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::continue_req, continue_req)) {
+ VIMAP_PARSER_GET(IMAPParser::response_data, response_data);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::continue_req> continue_req;
+ std::unique_ptr <IMAPParser::response_data> response_data;
+ };
+
+
+ //
+ // response_fatal ::= "*" SPACE resp_cond_bye CRLF
+ // ;; Server closes connection immediately
+ //
+
+ DECLARE_COMPONENT(response_fatal)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_cond_bye, resp_cond_bye);
+
+ if (!parser.isStrict()) {
+
+ // Allow SPACEs at end of line
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ ;
+ }
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_cond_bye> resp_cond_bye;
+ };
+
+
+ //
+ // response_tagged ::= tag SPACE resp_cond_state CRLF
+ //
+
+ DECLARE_COMPONENT(response_tagged)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::xtag, tag);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::resp_cond_state, resp_cond_state);
+
+ if (!parser.isStrict()) {
+
+ // Allow SPACEs at end of line
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ ;
+ }
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::xtag> tag;
+ std::unique_ptr <IMAPParser::resp_cond_state> resp_cond_state;
+ };
+
+
+ //
+ // response_done ::= response_tagged / response_fatal
+ //
+
+ DECLARE_COMPONENT(response_done)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::response_tagged, response_tagged)) {
+ VIMAP_PARSER_GET(IMAPParser::response_fatal, response_fatal);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::response_tagged> response_tagged;
+ std::unique_ptr <IMAPParser::response_fatal> response_fatal;
+ };
+
+
+ //
+ // response ::= *(continue_req / response_data) response_done
+ //
+
+ DECLARE_COMPONENT(response)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ string curLine = line;
+ bool partial = false; // partial response
+
+ IMAPParser::continue_req_or_response_data* resp = NULL;
+
+ while ((resp = parser.get <IMAPParser::continue_req_or_response_data>(curLine, &pos))) {
+
+ continue_req_or_response_data.push_back(
+ std::move(
+ std::unique_ptr <IMAPParser::continue_req_or_response_data>(resp)
+ )
+ );
+
+ // Partial response (continue_req)
+ if (resp->continue_req) {
+ partial = true;
+ break;
+ }
+
+ // We have read a CRLF, read another line
+ curLine = parser.readLine();
+ pos = 0;
+ }
+
+ if (!partial) {
+ response_done.reset(parser.get <IMAPParser::response_done>(curLine, &pos));
+ VIMAP_PARSER_FAIL_UNLESS(response_done);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ bool isBad() const {
+
+ if (!response_done) { // incomplete (partial) response
+ return true;
+ }
+
+ if (response_done->response_fatal) {
+ return true;
+ }
+
+ if (response_done->response_tagged->resp_cond_state->status == IMAPParser::resp_cond_state::BAD) {
+
+ return true;
+ }
+
+ return false;
+ }
+
+ void setErrorLog(const string& errorLog) {
+
+ m_errorLog = errorLog;
+ }
+
+ const string& getErrorLog() const {
+
+ return m_errorLog;
+ }
+
+
+ std::vector <std::unique_ptr <IMAPParser::continue_req_or_response_data>> continue_req_or_response_data;
+ std::unique_ptr <IMAPParser::response_done> response_done;
+
+ private:
+
+ string m_errorLog;
+ };
+
+
+ //
+ // greeting ::= "*" SPACE (resp_cond_auth / resp_cond_bye) CRLF
+ //
+
+ DECLARE_COMPONENT(greeting)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::resp_cond_auth, resp_cond_auth)) {
+ VIMAP_PARSER_GET(IMAPParser::resp_cond_bye, resp_cond_bye);
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ void setErrorLog(const string& errorLog) {
+
+ m_errorLog = errorLog;
+ }
+
+ const string& getErrorLog() const {
+
+ return m_errorLog;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_cond_auth> resp_cond_auth;
+ std::unique_ptr <IMAPParser::resp_cond_bye> resp_cond_bye;
+
+ private:
+
+ string m_errorLog;
+ };
+
+
+
+ //
+ // The main functions used to parse a response
+ //
+
+ response* readResponse(const IMAPTag& tag, literalHandler* lh = NULL) {
+
+ while (true) {
+
+ auto it = m_pendingResponses.find(std::string(tag));
+
+ if (it != m_pendingResponses.end()) {
+ auto* resp = it->second;
+ m_pendingResponses.erase(it);
+ return resp;
+ }
+
+ size_t pos = 0;
+ string line = readLine();
+
+ m_literalHandler = lh;
+ response* resp = get <response>(line, &pos);
+ m_literalHandler = NULL;
+
+ if (!resp) {
+ throw exceptions::invalid_response("", m_errorResponseLine);
+ }
+
+ resp->setErrorLog(lastLine());
+
+ // If there is a continue_req, return the response immediately
+ for (auto &respData : resp->continue_req_or_response_data) {
+ if (respData->continue_req) {
+ return resp;
+ }
+ }
+
+ // Else, return response if the tag is the one we expect
+ if (resp->response_done && resp->response_done->response_tagged &&
+ resp->response_done->response_tagged->tag) {
+
+ if (tag == resp->response_done->response_tagged->tag->tagString) {
+ return resp;
+ } else {
+ // Not our response tag, cache it for later
+ m_pendingResponses[resp->response_done->response_tagged->tag->tagString] = resp;
+ }
+ } else {
+ // Untagged response
+ return resp;
+ }
+ }
+ }
+
+
+ greeting* readGreeting() {
+
+ size_t pos = 0;
+ string line = readLine();
+
+ greeting* greet = get <greeting>(line, &pos);
+
+ if (!greet) {
+ throw exceptions::invalid_response("", m_errorResponseLine);
+ }
+
+ greet->setErrorLog(lastLine());
+
+ return greet;
+ }
+
+
+ /** Parse a token and advance.
+ * If the token has been parsed successfully, a raw pointer to it
+ * will be returned. The caller is responsible to free the memory.
+ *
+ * @param TYPE token type (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @return a raw pointer to the parsed token, or NULL otherwise
+ */
+ template <class TYPE>
+ TYPE* get(string& line, size_t* currentPos) {
+
+ component* resp = new TYPE;
+ return internalGet <TYPE>(resp, line, currentPos);
+ }
+
+ /** Parse a token which takes 2 arguments and advance.
+ * If the token has been parsed successfully, a raw pointer to it
+ * will be returned. The caller is responsible to free the memory.
+ *
+ * @param TYPE token type (class)
+ * @param ARG1_TYPE type of argument #1 (class)
+ * @param ARG2_TYPE type of argument #2 (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @param arg1 value of argument 1 to be passed to the token
+ * @param arg2 value of argument 2 to be passed to the token
+ * @return a raw pointer to the parsed token, or NULL otherwise
+ */
+ template <class TYPE, class ARG1_TYPE, class ARG2_TYPE>
+ TYPE* getWithArgs(string& line, size_t* currentPos, ARG1_TYPE arg1, ARG2_TYPE arg2) {
+
+ component* resp = new TYPE(arg1, arg2);
+ return internalGet <TYPE>(resp, line, currentPos);
+ }
+
+private:
+
+ template <class TYPE>
+ TYPE* internalGet(component* resp, string& line, size_t* currentPos) {
+
+ const size_t oldPos = *currentPos;
+
+ if (!resp->parse(*this, line, currentPos)) {
+
+ *currentPos = oldPos;
+
+ delete resp;
+
+ return NULL;
+ }
+
+ return static_cast <TYPE*>(resp);
+ }
+
+ const string lastLine() const {
+
+ // Remove blanks and new lines at the end of the line.
+ string line(m_lastLine);
+
+ string::const_iterator it = line.end();
+ int count = 0;
+
+ while (it != line.begin()) {
+
+ const unsigned char c = *(it - 1);
+
+ if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {
+ break;
+ }
+
+ ++count;
+ --it;
+ }
+
+ line.resize(line.length() - count);
+
+ return (line);
+ }
+
+public:
+
+ /** Check for a token and advance.
+ *
+ * @param TYPE token type (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @return true if the token has been parsed, or false otherwise
+ */
+ template <class TYPE>
+ bool check(string& line, size_t* currentPos) {
+
+ const size_t oldPos = *currentPos;
+
+ TYPE term;
+
+ if (!term.parse(*this, line, currentPos)) {
+ *currentPos = oldPos;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /** Check for a token which takes an argument and advance.
+ *
+ * @param TYPE token type (class)
+ * @param ARG_TYPE argument type (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @param arg argument to be passed to the token
+ * @return true if the token has been parsed, or false otherwise
+ */
+ template <class TYPE, class ARG_TYPE>
+ bool checkWithArg(string& line, size_t* currentPos, const ARG_TYPE arg) {
+
+ const size_t oldPos = *currentPos;
+
+ TYPE term(arg);
+
+ if (!term.parse(*this, line, currentPos)) {
+ *currentPos = oldPos;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+
+private:
+
+ weak_ptr <socket> m_socket;
+ shared_ptr <tracer> m_tracer;
+
+ utility::progressListener* m_progress;
+
+ bool m_strict;
+
+ literalHandler* m_literalHandler;
+
+ weak_ptr <timeoutHandler> m_timeoutHandler;
+
+
+ string m_buffer;
+
+ string m_lastLine;
+ string m_errorResponseLine;
+
+ std::map <std::string, response*> m_pendingResponses;
+
+public:
+
+ /** Read a line from the input buffer. The function blocks until a
+ * complete line is read from the buffer. Position in input buffer
+ * will be updated.
+ *
+ * @return next line
+ */
+ const string readLine() {
+
+ size_t pos;
+
+ while ((pos = m_buffer.find('\n')) == string::npos) {
+ read();
+ }
+
+ string line;
+ line.resize(pos + 1);
+ std::copy(m_buffer.begin(), m_buffer.begin() + pos + 1, line.begin());
+
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + pos + 1);
+
+ m_lastLine = line;
+
+#if DEBUG_RESPONSE
+ std::cout << std::endl << "Read line:" << std::endl << line << std::endl;
+#endif
+
+ if (m_tracer) {
+ string::size_type len = line.length();
+ while (len != 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) --len;
+ m_tracer->traceReceive(line.substr(0, len));
+ }
+
+ return (line);
+ }
+
+ /** Fill in the input buffer with data available from the socket stream.
+ * The function blocks until some data is available.
+ */
+ void read() {
+
+ string receiveBuffer;
+
+ shared_ptr <timeoutHandler> toh = m_timeoutHandler.lock();
+ shared_ptr <socket> sok = m_socket.lock();
+
+ if (toh) {
+ toh->resetTimeOut();
+ }
+
+ while (receiveBuffer.empty()) {
+
+ // Check whether the time-out delay is elapsed
+ if (toh && toh->isTimeOut()) {
+ if (!toh->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+ }
+
+ // We have received data: reset the time-out counter
+ sok->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+
+ if (sok->getStatus() & socket::STATUS_WANT_WRITE) {
+ sok->waitForWrite();
+ } else {
+ sok->waitForRead();
+ }
+
+ continue;
+ }
+
+ // We have received data ...
+ if (toh) {
+ toh->resetTimeOut();
+ }
+ }
+
+ m_buffer += receiveBuffer;
+ }
+
+
+ void readLiteral(literalHandler::target& buffer, size_t count) {
+
+ size_t len = 0;
+ string receiveBuffer;
+
+ shared_ptr <timeoutHandler> toh = m_timeoutHandler.lock();
+ shared_ptr <socket> sok = m_socket.lock();
+
+ if (m_progress) {
+ m_progress->start(count);
+ }
+
+ if (toh) {
+ toh->resetTimeOut();
+ }
+
+ if (!m_buffer.empty()) {
+
+ if (m_buffer.length() > count) {
+
+ buffer.putData(string(m_buffer.begin(), m_buffer.begin() + count));
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + count);
+ len = count;
+
+ } else {
+
+ len += m_buffer.length();
+ buffer.putData(m_buffer);
+ m_buffer.clear();
+ }
+ }
+
+ while (len < count) {
+
+ // Check whether the time-out delay is elapsed
+ if (toh && toh->isTimeOut()) {
+
+ if (!toh->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ toh->resetTimeOut();
+ }
+
+ // Receive data from the socket
+ sok->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+
+ if (sok->getStatus() & socket::STATUS_WANT_WRITE) {
+ sok->waitForWrite();
+ } else {
+ sok->waitForRead();
+ }
+
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (toh) {
+ toh->resetTimeOut();
+ }
+
+ if (len + receiveBuffer.length() > count) {
+
+ const size_t remaining = count - len;
+
+ // Get the needed amount of data
+ buffer.putData(string(receiveBuffer.begin(), receiveBuffer.begin() + remaining));
+
+ // Put the remaining data into the internal response buffer
+ receiveBuffer.erase(receiveBuffer.begin(), receiveBuffer.begin() + remaining);
+ m_buffer += receiveBuffer;
+
+ len = count;
+
+ } else {
+
+ buffer.putData(receiveBuffer);
+ len += receiveBuffer.length();
+ }
+
+ // Notify progress
+ if (m_progress) {
+ m_progress->progress(len, count);
+ }
+ }
+
+ if (m_tracer) {
+ m_tracer->traceReceiveBytes(count);
+ }
+
+ if (m_progress) {
+ m_progress->stop(count);
+ }
+ }
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#undef VIMAP_PARSER_FAIL
+#undef VIMAP_PARSER_FAIL_UNLESS
+#undef VIMAP_PARSER_CHECK
+#undef VIMAP_PARSER_TRY_CHECK
+#undef VIMAP_PARSER_GET
+#undef VIMAP_PARSER_GET
+#undef VIMAP_PARSER_TRY_GET
+#undef VIMAP_PARSER_TRY_GET
+#undef VIMAP_PARSER_GET_PUSHBACK
+#undef VIMAP_PARSER_CHECK_WITHARG
+#undef VIMAP_PARSER_TRY_CHECK_WITHARG
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPPARSER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPSStore.cpp b/vmime-master/src/vmime/net/imap/IMAPSStore.cpp
new file mode 100644
index 0000000..dd9c318
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPSStore.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPSStore.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPSStore::IMAPSStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : IMAPStore(sess, auth, true) {
+
+}
+
+
+IMAPSStore::~IMAPSStore() {
+
+}
+
+
+const string IMAPSStore::getProtocolName() const {
+
+ return "imaps";
+}
+
+
+
+// Service infos
+
+IMAPServiceInfos IMAPSStore::sm_infos(true);
+
+
+const serviceInfos& IMAPSStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& IMAPSStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPSStore.hpp b/vmime-master/src/vmime/net/imap/IMAPSStore.hpp
new file mode 100644
index 0000000..e18a067
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPSStore.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPSSTORE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPSSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPStore.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+/** IMAPS store service.
+ */
+class VMIME_EXPORT IMAPSStore : public IMAPStore {
+
+public:
+
+ IMAPSStore(const shared_ptr <session>& sess, const shared_ptr <security::authenticator>& auth);
+ ~IMAPSStore();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+private:
+
+ static IMAPServiceInfos sm_infos;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPSSTORE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp
new file mode 100644
index 0000000..baed6ba
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp
@@ -0,0 +1,135 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPServiceInfos::IMAPServiceInfos(const bool imaps)
+ : m_imaps(imaps) {
+
+}
+
+
+const string IMAPServiceInfos::getPropertyPrefix() const {
+
+ if (m_imaps) {
+ return "store.imaps.";
+ } else {
+ return "store.imap.";
+ }
+}
+
+
+const IMAPServiceInfos::props& IMAPServiceInfos::getProperties() const {
+
+ static props imapProps = {
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "143"),
+ };
+
+ static props imapsProps = {
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "993"),
+ };
+
+ return m_imaps ? imapsProps : imapProps;
+}
+
+
+const std::vector <serviceInfos::property> IMAPServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ list.push_back(p.PROPERTY_OPTIONS_SASL);
+ list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ list.push_back(p.PROPERTY_AUTH_USERNAME);
+ list.push_back(p.PROPERTY_AUTH_PASSWORD);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (!m_imaps) {
+ list.push_back(p.PROPERTY_CONNECTION_TLS);
+ list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED);
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ list.push_back(p.PROPERTY_SERVER_ADDRESS);
+ list.push_back(p.PROPERTY_SERVER_PORT);
+
+ return list;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp
new file mode 100644
index 0000000..73fca7a
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp
@@ -0,0 +1,89 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+/** Information about IMAP service.
+ */
+class VMIME_EXPORT IMAPServiceInfos : public serviceInfos {
+
+public:
+
+ IMAPServiceInfos(const bool imaps);
+
+ struct props {
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ serviceInfos::property PROPERTY_OPTIONS_SASL;
+ serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ serviceInfos::property PROPERTY_AUTH_USERNAME;
+ serviceInfos::property PROPERTY_AUTH_PASSWORD;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ serviceInfos::property PROPERTY_CONNECTION_TLS;
+ serviceInfos::property PROPERTY_CONNECTION_TLS_REQUIRED;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ serviceInfos::property PROPERTY_SERVER_ADDRESS;
+ serviceInfos::property PROPERTY_SERVER_PORT;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+
+private:
+
+ const bool m_imaps;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPStore.cpp b/vmime-master/src/vmime/net/imap/IMAPStore.cpp
new file mode 100644
index 0000000..eafa444
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPStore.cpp
@@ -0,0 +1,287 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include <map>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPStore::IMAPStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured
+)
+ : store(sess, getInfosInstance(), auth),
+ m_connection(null),
+ m_isIMAPS(secured) {
+
+}
+
+
+IMAPStore::~IMAPStore() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string IMAPStore::getProtocolName() const {
+
+ return "imap";
+}
+
+
+shared_ptr <folder> IMAPStore::getRootFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return make_shared <IMAPFolder>(
+ folder::path(),
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>()
+ );
+}
+
+
+shared_ptr <folder> IMAPStore::getDefaultFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return make_shared <IMAPFolder>(
+ folder::path::component("INBOX"),
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>()
+ );
+}
+
+
+shared_ptr <folder> IMAPStore::getFolder(const folder::path& path) {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return make_shared <IMAPFolder>(
+ path,
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>()
+ );
+}
+
+
+bool IMAPStore::isValidFolderName(const folder::path::component& /* name */) const {
+
+ return true;
+}
+
+
+void IMAPStore::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ m_connection = make_shared <IMAPConnection>(
+ dynamicCast <IMAPStore>(shared_from_this()), getAuthenticator()
+ );
+
+ m_connection->connect();
+}
+
+
+bool IMAPStore::isConnected() const {
+
+ return m_connection && m_connection->isConnected();
+}
+
+
+bool IMAPStore::isIMAPS() const {
+
+ return m_isIMAPS;
+}
+
+
+bool IMAPStore::isSecuredConnection() const {
+
+ if (!m_connection) {
+ return false;
+ }
+
+ return m_connection->isSecuredConnection();
+}
+
+
+shared_ptr <connectionInfos> IMAPStore::getConnectionInfos() const {
+
+ if (!m_connection) {
+ return null;
+ }
+
+ return m_connection->getConnectionInfos();
+}
+
+
+shared_ptr <IMAPConnection> IMAPStore::getConnection() {
+
+ return m_connection;
+}
+
+
+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_connection = null;
+}
+
+
+void IMAPStore::noop() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ IMAPCommand::NOOP()->send(m_connection);
+
+ scoped_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", resp->getErrorLog());
+ }
+
+
+ for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it) {
+
+ if ((*it)->isOpen()) {
+ (*it)->noop();
+ }
+ }
+}
+
+
+shared_ptr <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);
+ }
+}
+
+
+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
+
+IMAPServiceInfos IMAPStore::sm_infos(false);
+
+
+const serviceInfos& IMAPStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& IMAPStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPStore.hpp b/vmime-master/src/vmime/net/imap/IMAPStore.hpp
new file mode 100644
index 0000000..018c195
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPStore.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/store.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/imap/IMAPServiceInfos.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPParser;
+class IMAPTag;
+class IMAPFolder;
+
+
+/** IMAP store service.
+ */
+class VMIME_EXPORT IMAPStore : public store {
+
+ friend class IMAPFolder;
+ friend class IMAPMessage;
+ friend class IMAPConnection;
+
+public:
+
+ IMAPStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured = false
+ );
+
+ ~IMAPStore();
+
+ const string getProtocolName() const;
+
+ shared_ptr <folder> getDefaultFolder();
+ shared_ptr <folder> getRootFolder();
+ shared_ptr <folder> getFolder(const folder::path& path);
+
+ bool isValidFolderName(const folder::path::component& name) const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ int getCapabilities() const;
+
+ bool isIMAPS() const;
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+ shared_ptr <IMAPConnection> getConnection();
+
+protected:
+
+ // Connection
+ shared_ptr <IMAPConnection> m_connection;
+
+
+
+ shared_ptr <IMAPConnection> connection();
+
+
+ void registerFolder(IMAPFolder* folder);
+ void unregisterFolder(IMAPFolder* folder);
+
+ std::list <IMAPFolder*> m_folders;
+
+ const bool m_isIMAPS; // Use IMAPS
+
+
+ static IMAPServiceInfos sm_infos;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPTag.cpp b/vmime-master/src/vmime/net/imap/IMAPTag.cpp
new file mode 100644
index 0000000..52cd212
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPTag.cpp
@@ -0,0 +1,148 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#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);
+ generate();
+}
+
+
+IMAPTag::IMAPTag(const IMAPTag& tag)
+ : object(),
+ m_number(tag.m_number) {
+
+ m_tag.resize(4);
+ generate();
+}
+
+
+IMAPTag::IMAPTag()
+ : m_number(1) {
+
+ m_tag.resize(4);
+ generate();
+}
+
+
+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;
+}
+
+
+bool IMAPTag::operator<(const IMAPTag &other) const {
+
+ return m_number < other.m_number;
+}
+
+
+bool IMAPTag::operator==(const IMAPTag &other) const {
+
+ return m_number == other.m_number;
+}
+
+
+bool IMAPTag::operator!=(const IMAPTag &other) const {
+
+ return m_number != other.m_number;
+}
+
+
+bool IMAPTag::operator==(const std::string &tag) const {
+
+ return m_tag == tag;
+}
+
+
+int IMAPTag::maximumNumber() const {
+
+ return sm_maxNumber - 1;
+}
+
+
+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] = static_cast <char>('0' + (m_number % 1000) / 100);
+ m_tag[2] = static_cast <char>('0' + (m_number % 100) / 10);
+ m_tag[3] = static_cast <char>('0' + m_number % 10);
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPTag.hpp b/vmime-master/src/vmime/net/imap/IMAPTag.hpp
new file mode 100644
index 0000000..cbab942
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPTag.hpp
@@ -0,0 +1,85 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class VMIME_EXPORT IMAPTag : public object {
+
+private:
+
+ IMAPTag(const int number);
+
+public:
+
+ IMAPTag();
+ IMAPTag(const IMAPTag& tag);
+
+ IMAPTag& operator++(); // ++IMAPTag
+ const IMAPTag operator++(int); // IMAPTag++
+
+ int maximumNumber() const;
+ int number() const;
+
+ operator string() const;
+
+ bool operator<(const IMAPTag &other) const;
+ bool operator==(const IMAPTag &other) const;
+ bool operator!=(const IMAPTag &other) const;
+
+ bool operator==(const std::string &tag) const;
+
+private:
+
+ void generate();
+
+ static const int sm_maxNumber;
+
+ int m_number;
+ string m_tag;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPUtils.cpp b/vmime-master/src/vmime/net/imap/IMAPUtils.cpp
new file mode 100644
index 0000000..59b1e18
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPUtils.cpp
@@ -0,0 +1,854 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+// static
+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() ; 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 (size_t 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];
+
+ // iconv() is buggy with UTF-8 to UTF-7 conversion, so we do it "by hand".
+ // This code is largely inspired from "imap/utf7.c", in mutt 1.4.
+ // Copyright (C) 2000 Edmund Grimley Evans <edmundo@rano.org>
+
+ // WARNING: This may throw "exceptions::charset_conv_error"
+ const string cvt = text.getConvertedText(charset(charsets::UTF_8));
+
+ // In the worst case we convert 2 chars to 7 chars.
+ // For example: "\x10&\x10&..." -> "&ABA-&-&ABA-&-...".
+ string out;
+ out.reserve((cvt.length() / 2) * 7 + 6);
+
+ int b = 0, k = 0;
+ bool base64 = false;
+
+ size_t remaining = cvt.length();
+
+ for (size_t i = 0, len = cvt.length() ; i < len ; ) {
+
+ const unsigned char c = cvt[i];
+
+ // Replace hierarchy separator with an equivalent UTF-7 Base64 sequence
+ if (!base64 && c == hierarchySeparator) {
+
+ out += "&" + hsUTF7 + "-";
+
+ ++i;
+ --remaining;
+ continue;
+ }
+
+ size_t n = 0;
+ int ch = 0;
+
+ if (c < 0x80) {
+ ch = c, n = 0;
+ } else if (c < 0xc2) {
+ return "";
+ } else if (c < 0xe0) {
+ ch = c & 0x1f, n = 1;
+ } else if (c < 0xf0) {
+ ch = c & 0x0f, n = 2;
+ } else if (c < 0xf8) {
+ ch = c & 0x07, n = 3;
+ } else if (c < 0xfc) {
+ ch = c & 0x03, n = 4;
+ } else if (c < 0xfe) {
+ ch = c & 0x01, n = 5;
+ } else {
+ return "";
+ }
+
+ if (n > remaining) {
+ return ""; // error
+ }
+
+ ++i;
+ --remaining;
+
+ for (size_t j = 0 ; j < n ; j++) {
+
+ if ((cvt[i + j] & 0xc0) != 0x80) {
+ return ""; // error
+ }
+
+ ch = (ch << 6) | (cvt[i + j] & 0x3f);
+ }
+
+ if (n > 1 && !(ch >> (n * 5 + 1))) {
+ return ""; // error
+ }
+
+ i += n;
+ remaining -= n;
+
+ if (ch < 0x20 || ch >= 0x7f) {
+
+ if (!base64) {
+ out += '&';
+ base64 = true;
+ b = 0;
+ k = 10;
+ }
+
+ if (ch & ~0xffff) {
+ ch = 0xfffe;
+ }
+
+ out += base64alphabet[b | ch >> k];
+
+ k -= 6;
+
+ for ( ; k >= 0 ; k -= 6) {
+ out += base64alphabet[(ch >> k) & 0x3f];
+ }
+
+ b = (ch << (-k)) & 0x3f;
+ k += 16;
+
+ } else {
+
+ if (base64) {
+
+ if (k > 10) {
+ out += base64alphabet[b];
+ }
+
+ out += '-';
+ base64 = false;
+ }
+
+ out += static_cast <char>(ch);
+
+ if (ch == '&') {
+ out += '-';
+ }
+ }
+ }
+
+ if (base64) {
+
+ if (k > 10) {
+ out += base64alphabet[b];
+ }
+
+ out += '-';
+ }
+
+ 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;
+ bool plusOutput = 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;
+ plusOutput = false;
+ } else {
+ out += '&';
+ }
+
+ break;
+ }
+ // End of Base64 sequence (or "&-" --> "&")
+ case '-': {
+
+ if (inB64sequence && prev == '&') { // special case "&-" --> "&"
+ out += '&';
+ } else {
+ out += '-';
+ }
+
+ inB64sequence = false;
+ break;
+ }
+ // ',' is used instead of '/' in modified Base64
+ case ',': {
+
+ if (inB64sequence && !plusOutput) {
+ out += '+';
+ plusOutput = true;
+ }
+
+ out += (inB64sequence ? '/' : ',');
+ break;
+ }
+ default: {
+
+ if (inB64sequence && !plusOutput) {
+ out += '+';
+ plusOutput = true;
+ }
+
+ 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));
+}
+
+
+// static
+void IMAPUtils::mailboxFlagsToFolderAttributes(
+ const shared_ptr <const IMAPConnection>& cnt,
+ const folder::path &path,
+ const IMAPParser::mailbox_flag_list& list,
+ folderAttributes& attribs
+) {
+
+ int specialUse = folderAttributes::SPECIALUSE_NONE;
+ int type = folderAttributes::TYPE_CONTAINS_MESSAGES | folderAttributes::TYPE_CONTAINS_FOLDERS;
+ int flags = 0;
+
+ // If CHILDREN extension (RFC-3348) is not supported, assume folder has children
+ // as we have no hint about it
+ if (!cnt->hasCapability("CHILDREN")) {
+ flags |= folderAttributes::FLAG_HAS_CHILDREN;
+ }
+
+ for (auto it = list.flags.begin() ; it != list.flags.end() ; ++it) {
+
+ switch ((*it)->type) {
+
+ case IMAPParser::mailbox_flag::NOSELECT:
+
+ type &= ~folderAttributes::TYPE_CONTAINS_MESSAGES;
+ flags |= folderAttributes::FLAG_NO_OPEN;
+ break;
+
+ case IMAPParser::mailbox_flag::NOINFERIORS:
+ case IMAPParser::mailbox_flag::HASNOCHILDREN:
+
+ flags &= ~folderAttributes::FLAG_HAS_CHILDREN;
+ break;
+
+ case IMAPParser::mailbox_flag::HASCHILDREN:
+
+ flags |= folderAttributes::FLAG_HAS_CHILDREN;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_ALL:
+
+ specialUse = folderAttributes::SPECIALUSE_ALL;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_ARCHIVE:
+
+ specialUse = folderAttributes::SPECIALUSE_ARCHIVE;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_DRAFTS:
+
+ specialUse = folderAttributes::SPECIALUSE_DRAFTS;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_FLAGGED:
+
+ specialUse = folderAttributes::SPECIALUSE_FLAGGED;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_JUNK:
+
+ specialUse = folderAttributes::SPECIALUSE_JUNK;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_SENT:
+
+ specialUse = folderAttributes::SPECIALUSE_SENT;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_TRASH:
+
+ specialUse = folderAttributes::SPECIALUSE_TRASH;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_IMPORTANT:
+
+ specialUse = folderAttributes::SPECIALUSE_IMPORTANT;
+ break;
+
+ default:
+
+ break;
+ }
+ }
+
+ if (path.getSize() == 1 && path.getLastComponent().getBuffer() == "INBOX") {
+ specialUse = folderAttributes::SPECIALUSE_INBOX;
+ }
+
+ attribs.setSpecialUse(specialUse);
+ attribs.setType(type);
+ attribs.setFlags(flags);
+}
+
+
+int IMAPUtils::messageFlagsFromFlags(const IMAPParser::flag_list& list) {
+
+ int flags = 0;
+
+ for (auto &flag : list.flags) {
+
+ switch (flag->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;
+
+ case IMAPParser::flag::DRAFT:
+
+ flags |= message::FLAG_DRAFT;
+ break;
+
+ default:
+ //case IMAPParser::flag::UNKNOWN:
+
+ break;
+ }
+ }
+
+ return flags;
+}
+
+
+// static
+const std::vector <string> IMAPUtils::messageFlagList(const int flags) {
+
+ std::vector <string> flagList;
+
+ if (flags == -1) {
+ return flagList; // default flags
+ }
+
+ 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 (flags & message::FLAG_DRAFT) flagList.push_back("\\Draft");
+
+ return flagList;
+}
+
+
+// static
+const string IMAPUtils::dateTime(const vmime::datetime& date) {
+
+ std::ostringstream res;
+ res.imbue(std::locale::classic());
+
+ // 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();
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPUtils::buildFetchCommand(
+ const shared_ptr <IMAPConnection>& cnt,
+ const messageSet& msgs,
+ const fetchAttributes& options
+) {
+
+ // 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.has(fetchAttributes::SIZE)) {
+ items.push_back("RFC822.SIZE");
+ }
+
+ if (options.has(fetchAttributes::FLAGS)) {
+ items.push_back("FLAGS");
+ }
+
+ if (options.has(fetchAttributes::STRUCTURE)) {
+ items.push_back("BODYSTRUCTURE");
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+
+ items.push_back("UID");
+
+ // Also fetch MODSEQ if CONDSTORE is supported
+ if (cnt && cnt->hasCapability("CONDSTORE") && !cnt->isMODSEQDisabled()) {
+ items.push_back("MODSEQ");
+ }
+ }
+
+ if (options.has(fetchAttributes::FULL_HEADER)) {
+
+ items.push_back("RFC822.HEADER");
+
+ } else {
+
+ if (options.has(fetchAttributes::ENVELOPE)) {
+ items.push_back("ENVELOPE");
+ }
+
+ std::vector <string> headerFields;
+
+ if (options.has(fetchAttributes::CONTENT_INFO)) {
+ headerFields.push_back("CONTENT_TYPE");
+ }
+
+ if (options.has(fetchAttributes::IMPORTANCE)) {
+ headerFields.push_back("IMPORTANCE");
+ headerFields.push_back("X-PRIORITY");
+ }
+
+ // Also add custom header fields to fetch, if any
+ const std::vector <string> customHeaderFields = options.getHeaderFields();
+ std::copy(customHeaderFields.begin(), customHeaderFields.end(), std::back_inserter(headerFields));
+
+ 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 + ")]");
+ }
+ }
+
+ return IMAPCommand::FETCH(msgs, items);
+}
+
+
+// static
+void IMAPUtils::convertAddressList(
+ const IMAPParser::address_list& src,
+ mailboxList& dest
+) {
+
+ for (auto& addr : src.addresses) {
+
+ text name;
+ text::decodeAndUnfold(addr->addr_name->value, &name);
+
+ string email = addr->addr_mailbox->value
+ + "@" + addr->addr_host->value;
+
+ dest.appendMailbox(make_shared <mailbox>(name, email));
+ }
+}
+
+
+
+class IMAPUIDMessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ IMAPUIDMessageSetEnumerator()
+ : m_first(true) {
+
+ m_oss.imbue(std::locale::classic());
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":*";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":*";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ const std::string str() const {
+
+ return m_oss.str();
+ }
+
+private:
+
+ std::ostringstream m_oss;
+ bool m_first;
+};
+
+
+class IMAPMessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ for (size_t i = range.getFirst(), last = range.getLast() ; i <= last ; ++i) {
+ m_list.push_back(i);
+ }
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) {
+
+ // Not used
+ }
+
+ const std::vector <size_t>& list() const {
+
+ return m_list;
+ }
+
+public:
+
+ std::vector <size_t> m_list;
+};
+
+
+
+// static
+const string IMAPUtils::messageSetToSequenceSet(const messageSet& msgs) {
+
+ IMAPUIDMessageSetEnumerator en;
+ msgs.enumerate(en);
+
+ return en.str();
+}
+
+
+// static
+messageSet IMAPUtils::buildMessageSet(const IMAPParser::uid_set& uidSetRef) {
+
+ messageSet set = messageSet::empty();
+
+ const IMAPParser::uid_set* uidSet = &uidSetRef;
+
+ for ( ; uidSet ; uidSet = uidSet->next_uid_set.get()) {
+
+ if (uidSet->uid_range) {
+
+ set.addRange(
+ UIDMessageRange(
+ message::uid(uidSet->uid_range->uniqueid1->value),
+ message::uid(uidSet->uid_range->uniqueid2->value)
+ )
+ );
+
+ } else {
+
+ set.addRange(
+ UIDMessageRange(
+ message::uid(uidSet->uniqueid->value)
+ )
+ );
+ }
+ }
+
+ return set;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPUtils.hpp b/vmime-master/src/vmime/net/imap/IMAPUtils.hpp
new file mode 100644
index 0000000..d4bd135
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPUtils.hpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/types.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/net/folder.hpp"
+#include "vmime/net/message.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
+
+#include "vmime/mailboxList.hpp"
+
+#include <vector>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class VMIME_EXPORT 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);
+
+ /** Quote string if it contains IMAP-special characters.
+ *
+ * @param text string to quote
+ * @return quoted string
+ */
+ static const string quoteString(const string& text);
+
+ /** Parse mailbox flags and fill in folder attributes.
+ *
+ * @param cnt reference to current IMAP connection (for testing capabilities)
+ * @param path folder full path
+ * @param list list of mailbox flags
+ * @param attribs reference to an object holding folder attributes
+ */
+ static void mailboxFlagsToFolderAttributes(
+ const shared_ptr <const IMAPConnection>& cnt,
+ const folder::path &path,
+ const IMAPParser::mailbox_flag_list& list,
+ folderAttributes& attribs
+ );
+
+ static int messageFlagsFromFlags(const IMAPParser::flag_list& list);
+
+ static const std::vector <string> messageFlagList(const int flags);
+
+ /** Format a date/time to IMAP date/time format.
+ *
+ * @param date date/time to format
+ * @return IMAP-formatted date/time
+ */
+ static const string dateTime(const vmime::datetime& date);
+
+ /** Construct a fetch request for the specified messages, designated
+ * either by their sequence numbers or their UIDs.
+ *
+ * @param cnt connection
+ * @param msgs message set
+ * @param options fetch options
+ * @return fetch request
+ */
+ static shared_ptr <IMAPCommand> buildFetchCommand(
+ const shared_ptr <IMAPConnection>& cnt,
+ const messageSet& msgs,
+ const fetchAttributes& options
+ );
+
+ /** Convert a parser-style address list to a mailbox list.
+ *
+ * @param src input address list
+ * @param dest output mailbox list
+ */
+ static void convertAddressList(const IMAPParser::address_list& src, mailboxList& dest);
+
+ /** Returns an IMAP-formatted sequence set given a message set.
+ *
+ * @param msgs message set
+ * @return IMAP sequence set (eg. "1:5,7,15:*")
+ */
+ static const string messageSetToSequenceSet(const messageSet& msgs);
+
+ /** Constructs a message set from a parser 'uid_set' structure.
+ *
+ * @param uidSet UID set, as returned by the parser
+ * @return message set
+ */
+ static messageSet buildMessageSet(const IMAPParser::uid_set& uidSet);
+
+private:
+
+ static const string buildFetchRequestImpl
+ (const shared_ptr <IMAPConnection>& cnt, const string& mode, const string& set, const int options);
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/imap.hpp b/vmime-master/src/vmime/net/imap/imap.hpp
new file mode 100644
index 0000000..f25baa4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/imap.hpp
@@ -0,0 +1,35 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAP_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAP_HPP_INCLUDED
+
+
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPSStore.hpp"
+
+
+#endif // VMIME_NET_IMAP_IMAP_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp
new file mode 100644
index 0000000..e611949
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp
@@ -0,0 +1,569 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/format/courierMaildirFormat.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+courierMaildirFormat::courierMaildirFormat(const shared_ptr <context>& ctx)
+ : maildirFormat(ctx) {
+
+}
+
+
+const string courierMaildirFormat::getName() const {
+
+ return "courier";
+}
+
+
+void courierMaildirFormat::createFolder(const folder::path& path) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ rootDir->createDirectory(true);
+
+ newDir->createDirectory(false);
+ tmpDir->createDirectory(false);
+ curDir->createDirectory(false);
+
+ shared_ptr <utility::file> maildirFile = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ / utility::file::path::component("maildirfolder")
+ );
+
+ maildirFile->createFile();
+}
+
+
+void courierMaildirFormat::destroyFolder(const folder::path& path) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ // Recursively delete directories of subfolders
+ const std::vector <folder::path> folders = listFolders(path, true);
+
+ for (std::vector <folder::path>::size_type i = 0, n = folders.size() ; i < n ; ++i) {
+
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(folders[i], ROOT_DIRECTORY))
+ );
+ }
+
+ // Recursively delete the directory of this folder
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(path, ROOT_DIRECTORY))
+ );
+}
+
+
+void courierMaildirFormat::renameFolder(
+ const folder::path& oldPath,
+ const folder::path& newPath
+) {
+
+ const std::vector <folder::path> folders = listFolders(oldPath, true);
+
+ for (std::vector <folder::path>::size_type i = 0, n = folders.size() ; i < n ; ++i) {
+
+ const folder::path folderOldPath = folders[i];
+
+ folder::path folderNewPath = folderOldPath;
+ folderNewPath.renameParent(oldPath, newPath);
+
+ renameFolderImpl(folderOldPath, folderNewPath);
+ }
+
+ renameFolderImpl(oldPath, newPath);
+}
+
+
+void courierMaildirFormat::renameFolderImpl(
+ const folder::path& oldPath,
+ const folder::path& newPath
+) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path oldFSPath =
+ folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY);
+
+ const utility::file::path newFSPath =
+ folderPathToFileSystemPath(newPath, ROOT_DIRECTORY);
+
+ shared_ptr <utility::file> rootDir = fsf->create(oldFSPath);
+ rootDir->rename(newFSPath);
+}
+
+
+bool courierMaildirFormat::folderExists(const folder::path& path) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> maildirFile = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ / utility::file::path::component("maildirfolder")
+ );
+
+ bool exists = rootDir->exists() && rootDir->isDirectory() &&
+ newDir->exists() && newDir->isDirectory() &&
+ tmpDir->exists() && tmpDir->isDirectory() &&
+ curDir->exists() && curDir->isDirectory();
+
+ // If this is not the root folder, then a file named "maildirfolder"
+ // must also be present in the directory
+ if (!path.isRoot()) {
+ exists = exists && maildirFile->exists() && maildirFile->isFile();
+ }
+
+ return exists;
+}
+
+
+bool courierMaildirFormat::folderHasSubfolders(const folder::path& path) const {
+
+ std::vector <string> dirs;
+ return listDirectories(path, dirs, true);
+}
+
+
+const utility::file::path courierMaildirFormat::folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+) const {
+
+ // Virtual folder "/MyFolder/SubFolder" corresponds to physical
+ // directory "[store root]/.MyFolder.SubFolder"
+ utility::file::path fsPath = getContext()->getStore()->getFileSystemPath();
+
+ if (!path.isRoot()) {
+
+ string folderComp;
+
+ for (size_t i = 0, n = path.getSize() ; i < n ; ++i) {
+ folderComp += "." + toModifiedUTF7(path[i]);
+ }
+
+ fsPath /= utility::file::path::component(folderComp);
+ }
+
+ // Last component
+ switch (type) {
+
+ case ROOT_DIRECTORY:
+
+ // Nothing to add
+ break;
+
+ case NEW_DIRECTORY:
+
+ fsPath /= NEW_DIR;
+ break;
+
+ case CUR_DIRECTORY:
+
+ fsPath /= CUR_DIR;
+ break;
+
+ case TMP_DIRECTORY:
+
+ fsPath /= TMP_DIR;
+ break;
+
+ case CONTAINER_DIRECTORY:
+
+ // Not used
+ break;
+ }
+
+ return fsPath;
+}
+
+
+const std::vector <folder::path> courierMaildirFormat::listFolders(
+ const folder::path& root,
+ const bool recursive
+) const {
+
+ // First, list directories
+ std::vector <string> dirs;
+ listDirectories(root, dirs, false);
+
+ // Then, map directories to folders
+ std::vector <folder::path> folders;
+
+ for (std::vector <string>::size_type i = 0, n = dirs.size() ; i < n ; ++i) {
+
+ const string dir = dirs[i].substr(1) + ".";
+ folder::path path;
+
+ for (size_t pos = dir.find("."), prev = 0 ;
+ pos != string::npos ; prev = pos + 1, pos = dir.find(".", pos + 1)) {
+
+ const string comp = dir.substr(prev, pos - prev);
+ path /= fromModifiedUTF7(comp);
+ }
+
+ if (recursive || path.getSize() == root.getSize() + 1) {
+ folders.push_back(path);
+ }
+ }
+
+ return folders;
+}
+
+
+bool courierMaildirFormat::listDirectories(
+ const folder::path& root,
+ std::vector <string>& dirs,
+ const bool onlyTestForExistence
+) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ getContext()->getStore()->getFileSystemPath()
+ );
+
+ if (rootDir->exists()) {
+
+ // To speed up things, and if we are not searching in root folder,
+ // search for directories with a common prefix
+ string base;
+
+ if (!root.isRoot()) {
+ for (size_t i = 0, n = root.getSize() ; i < n ; ++i) {
+ base += "." + toModifiedUTF7(root[i]);
+ }
+ }
+
+ // Enumerate directories
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+
+ const string dir = file->getFullPath().getLastComponent().getBuffer();
+
+ if (base.empty() || (dir.length() > base.length() && dir.substr(0, base.length()) == base)) {
+
+ dirs.push_back(dir);
+
+ if (onlyTestForExistence) {
+ return true;
+ }
+ }
+ }
+ }
+
+ } else {
+
+ // No sub-folder
+ }
+
+ std::sort(dirs.begin(), dirs.end());
+
+ return !dirs.empty();
+}
+
+
+// static
+bool courierMaildirFormat::isSubfolderDirectory(const utility::file& file) {
+
+ // A directory which names starts with '.' may be a subfolder
+ if (file.isDirectory() &&
+ file.getFullPath().getLastComponent().getBuffer().length() >= 1 &&
+ file.getFullPath().getLastComponent().getBuffer()[0] == '.') {
+
+ return true;
+ }
+
+ return false;
+}
+
+
+// static
+const string courierMaildirFormat::toModifiedUTF7(const folder::path::component& text) {
+
+ // From http://www.courier-mta.org/?maildir.html:
+ //
+ // Folder names can contain any Unicode character, except for control
+ // characters. US-ASCII characters, U+0x0020 - U+0x007F, except for the
+ // period, forward-slash, and ampersand characters (U+0x002E, U+0x002F,
+ // and U+0x0026) represent themselves. The ampersand is represented by
+ // the two character sequence "&-". The period, forward slash, and non
+ // US-ASCII Unicode characters are represented using the UTF-7 character
+ // set, and encoded with a modified form of base64-encoding.
+ //
+ // The "&" character starts the modified base64-encoded sequence; the
+ // sequence is terminated by the "-" character. The sequence of 16-bit
+ // Unicode characters is written in big-endian order, and encoded using
+ // the base64-encoding method described in section 5.2 of RFC 1521, with
+ // the following modifications:
+ //
+ // * The "=" padding character is omitted. When decoding, an incomplete
+ // 16-bit character is discarded.
+ //
+ // * The comma character, "," is used in place of the "/" character in
+ // the base64 alphabet.
+ //
+ // For example, the word "Resume" with both "e"s being the e-acute
+ // character, U+0x00e9, is encoded as "R&AOk-sum&AOk-" (so a folder of
+ // that name would be a maildir subdirectory called ".R&AOk-sum&AOk-").
+ //
+
+ // 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;
+
+ 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,
+ // and simply UTF7-encoded out of a Base64 sequence
+ case '/': {
+
+ if (inB64sequence) {
+ out += ',';
+ } else {
+ out += "&Lw-";
+ }
+
+ break;
+ }
+ // Encode period (should not happen in a Base64 sequence)
+ case '.': {
+
+ out += "&Lg-";
+ break;
+ }
+ // '&' (0x26) is represented by the two-octet sequence "&-"
+ case '&': {
+
+ if (!inB64sequence) {
+ out += "&-";
+ } else {
+ out += '&';
+ }
+
+ break;
+ }
+ default: {
+
+ out += c;
+ break;
+ }
+ }
+ }
+
+ return out;
+}
+
+
+// static
+const folder::path::component courierMaildirFormat::fromModifiedUTF7(const string& text) {
+
+ // Transcode from modified UTF-7
+ 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));
+}
+
+
+bool courierMaildirFormat::supports() const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ getContext()->getStore()->getFileSystemPath()
+ );
+
+ if (rootDir->exists()) {
+
+ // Try to find a file named "maildirfolder", which indicates
+ // the Maildir is in Courier format
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+
+ shared_ptr <utility::file> folderFile = fsf->create(
+ file->getFullPath() / utility::file::path::component("maildirfolder")
+ );
+
+ if (folderFile->exists() && folderFile->isFile()) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp
new file mode 100644
index 0000000..7db1a83
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp
@@ -0,0 +1,127 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+/** Reads Courier/QMail Maildir format.
+ */
+class VMIME_EXPORT courierMaildirFormat : public maildirFormat {
+
+public:
+
+ courierMaildirFormat(const shared_ptr <context>& ctx);
+
+
+ /* Folder types:
+ *
+ * - ROOT_DIRECTORY: ~/Mail/.MyFolder
+ * - NEW_DIRECTORY: ~/Mail/.MyFolder/new
+ * - CUR_DIRECTORY: ~/Mail/.MyFolder/cur
+ * - TMP_DIRECTORY: ~/Mail/.MyFolder/tmp
+ * - CONTAINER_DIRECTORY: not used
+ */
+
+ const string getName() const;
+
+ void createFolder(const folder::path& path);
+ void destroyFolder(const folder::path& path);
+ void renameFolder(const folder::path& oldPath, const folder::path& newPath);
+
+ bool folderExists(const folder::path& path) const;
+ bool folderHasSubfolders(const folder::path& path) const;
+
+ const utility::file::path folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+ ) const;
+
+ const std::vector <folder::path> listFolders(
+ const folder::path& root,
+ const bool recursive
+ ) const;
+
+protected:
+
+ bool supports() const;
+
+
+ static const string toModifiedUTF7(const folder::path::component& text);
+ static const folder::path::component fromModifiedUTF7(const string& text);
+
+ void renameFolderImpl(const folder::path& oldPath, const folder::path& newPath);
+
+ /** Test whether the specified file system directory corresponds to
+ * a maildir subfolder. The name of the directory should start
+ * with a '.' to be listed as a subfolder.
+ *
+ * @param file reference to a file system directory
+ * @return true if the specified directory is a maildir subfolder,
+ * false otherwise
+ */
+ static bool isSubfolderDirectory(const utility::file& file);
+
+ /** List directories corresponding to folders which are (direct or
+ * indirect) children of specified folder.
+ *
+ * @param root root folder
+ * @param dirs list in which found directories will be added
+ * @param onlyTestForExistence if true, the function returns as soon
+ * as the first directory is found
+ * @return true if at least one directory has been found,
+ * false otherwise
+ */
+ bool listDirectories(
+ const folder::path& root,
+ std::vector <string>& dirs,
+ const bool onlyTestForExistence
+ ) const;
+};
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp
new file mode 100644
index 0000000..4eb89e8
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp
@@ -0,0 +1,337 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/format/kmailMaildirFormat.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+kmailMaildirFormat::kmailMaildirFormat(const shared_ptr <context>& ctx)
+ : maildirFormat(ctx) {
+
+}
+
+
+const string kmailMaildirFormat::getName() const {
+
+ return "kmail";
+}
+
+
+void kmailMaildirFormat::createFolder(const folder::path& path) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ rootDir->createDirectory(true);
+
+ newDir->createDirectory(false);
+ tmpDir->createDirectory(false);
+ curDir->createDirectory(false);
+}
+
+
+void kmailMaildirFormat::destroyFolder(const folder::path& path) {
+
+ // Delete 'folder' and '.folder.directory' directories
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(path, ROOT_DIRECTORY)) // root
+ );
+
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(path, CONTAINER_DIRECTORY)) // container
+ );
+}
+
+
+bool kmailMaildirFormat::folderExists(const folder::path& path) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ return rootDir->exists() && rootDir->isDirectory() &&
+ newDir->exists() && newDir->isDirectory() &&
+ tmpDir->exists() && tmpDir->isDirectory() &&
+ curDir->exists() && curDir->isDirectory();
+}
+
+
+const utility::file::path kmailMaildirFormat::folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+) const {
+
+ // Root path
+ utility::file::path fsPath = getContext()->getStore()->getFileSystemPath();
+
+ const size_t pathSize = path.getSize();
+ const size_t count = (type == CONTAINER_DIRECTORY
+ ? pathSize : (pathSize >= 1 ? pathSize - 1 : 0));
+
+ // Parent folders
+ for (size_t i = 0 ; i < count ; ++i) {
+
+ utility::file::path::component comp(path[i]);
+
+ // TODO: may not work with all encodings...
+ comp.setBuffer("." + comp.getBuffer() + ".directory");
+
+ fsPath /= comp;
+ }
+
+ // Last component
+ if (path.getSize() != 0 && type != CONTAINER_DIRECTORY) {
+
+ fsPath /= path.getLastComponent();
+
+ switch (type) {
+
+ case ROOT_DIRECTORY:
+
+ // Nothing to add
+ break;
+
+ case NEW_DIRECTORY:
+
+ fsPath /= NEW_DIR;
+ break;
+
+ case CUR_DIRECTORY:
+
+ fsPath /= CUR_DIR;
+ break;
+
+ case TMP_DIRECTORY:
+
+ fsPath /= TMP_DIR;
+ break;
+
+ case CONTAINER_DIRECTORY:
+
+ // Can't happen...
+ break;
+ }
+ }
+
+ return fsPath;
+}
+
+
+const std::vector <folder::path> kmailMaildirFormat::listFolders(
+ const folder::path& root,
+ const bool recursive
+) const {
+
+ std::vector <folder::path> list;
+ listFoldersImpl(list, root, recursive);
+
+ return list;
+}
+
+
+void kmailMaildirFormat::listFoldersImpl(
+ std::vector <folder::path>& list,
+ const folder::path& root,
+ const bool recursive
+) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(root, root.isEmpty() ? ROOT_DIRECTORY : CONTAINER_DIRECTORY)
+ );
+
+ if (rootDir->exists()) {
+
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+
+ const utility::path subPath = root / file->getFullPath().getLastComponent();
+
+ list.push_back(subPath);
+
+ if (recursive) {
+ listFoldersImpl(list, subPath, true);
+ }
+ }
+ }
+
+ } else {
+
+ // No sub-folder
+ }
+}
+
+
+// static
+bool kmailMaildirFormat::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;
+}
+
+
+void kmailMaildirFormat::renameFolder(const folder::path& oldPath, const folder::path& newPath) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY)
+ );
+ shared_ptr <utility::file> contDir = fsf->create(
+ folderPathToFileSystemPath(oldPath, CONTAINER_DIRECTORY)
+ );
+
+ try {
+
+ const utility::file::path newRootPath =
+ folderPathToFileSystemPath(newPath, ROOT_DIRECTORY);
+ const utility::file::path newContPath =
+ folderPathToFileSystemPath(newPath, CONTAINER_DIRECTORY);
+
+ rootDir->rename(newRootPath);
+
+ // Container directory may not exist, so ignore error when trying to rename it
+ try {
+ contDir->rename(newContPath);
+ } catch (exceptions::filesystem_exception& e) {
+ // Ignore
+ }
+
+ } catch (exceptions::filesystem_exception& e) {
+
+ // Revert to old location
+ const utility::file::path rootPath =
+ folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY);
+ const utility::file::path contPath =
+ folderPathToFileSystemPath(oldPath, CONTAINER_DIRECTORY);
+
+ try {
+ rootDir->rename(rootPath);
+ contDir->rename(contPath);
+ } catch (exceptions::filesystem_exception& e) {
+ // Ignore (not recoverable)
+ }
+
+ throw;
+ }
+}
+
+
+bool kmailMaildirFormat::folderHasSubfolders(const folder::path& path) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, CONTAINER_DIRECTORY)
+ );
+
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool kmailMaildirFormat::supports() const {
+
+ // This is the default
+ return true;
+}
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp
new file mode 100644
index 0000000..26b557a
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp
@@ -0,0 +1,115 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+/** Reads KMail Maildir format.
+ */
+class VMIME_EXPORT kmailMaildirFormat : public maildirFormat {
+
+public:
+
+ kmailMaildirFormat(const shared_ptr <context>& ctx);
+
+
+ /* Folder types:
+ *
+ * - ROOT_DIRECTORY: ~/Mail/MyFolder
+ * - NEW_DIRECTORY: ~/Mail/MyFolder/new
+ * - CUR_DIRECTORY: ~/Mail/MyFolder/cur
+ * - TMP_DIRECTORY: ~/Mail/MyFolder/tmp
+ * - CONTAINER_DIRECTORY: ~/Mail/.MyFolder.directory
+ */
+
+ const string getName() const;
+
+ void createFolder(const folder::path& path);
+ void destroyFolder(const folder::path& path);
+ void renameFolder(const folder::path& oldPath, const folder::path& newPath);
+
+ bool folderExists(const folder::path& path) const;
+ bool folderHasSubfolders(const folder::path& path) const;
+
+ const utility::file::path folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+ ) const;
+
+ const std::vector <folder::path> listFolders(
+ const folder::path& root,
+ const bool recursive
+ ) const;
+
+protected:
+
+ bool supports() const;
+
+
+ /** Recursive implementation of listFolders().
+ */
+ void listFoldersImpl(
+ std::vector <folder::path>& list,
+ const folder::path& root,
+ const bool recursive
+ ) const;
+
+ /** Test whether the specified file system directory corresponds to
+ * a maildir subfolder. The name of the directory should not start
+ * with '.' to be listed as a subfolder.
+ *
+ * @param file reference to a file system directory
+ * @return true if the specified directory is a maildir subfolder,
+ * false otherwise
+ */
+ static bool isSubfolderDirectory(const utility::file& file);
+};
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#endif // VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/maildir.hpp b/vmime-master/src/vmime/net/maildir/maildir.hpp
new file mode 100644
index 0000000..8835bf4
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildir.hpp
@@ -0,0 +1,34 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED
+
+
+#include "vmime/net/maildir/maildirFolder.hpp"
+#include "vmime/net/maildir/maildirFolderStatus.hpp"
+#include "vmime/net/maildir/maildirMessage.hpp"
+#include "vmime/net/maildir/maildirStore.hpp"
+
+
+#endif // VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolder.cpp b/vmime-master/src/vmime/net/maildir/maildirFolder.cpp
new file mode 100644
index 0000000..8c02025
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolder.cpp
@@ -0,0 +1,1365 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFolder.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirMessage.hpp"
+#include "vmime/net/maildir/maildirUtils.hpp"
+#include "vmime/net/maildir/maildirFormat.hpp"
+#include "vmime/net/maildir/maildirFolderStatus.hpp"
+
+#include "vmime/message.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirFolder::maildirFolder(
+ const folder::path& path,
+ const shared_ptr <maildirStore>& store
+)
+ : m_store(store),
+ m_path(path),
+ m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()),
+ m_mode(-1),
+ m_open(false),
+ m_unreadMessageCount(0),
+ m_messageCount(0) {
+
+ store->registerFolder(this);
+}
+
+
+maildirFolder::~maildirFolder() {
+
+ try {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (store) {
+
+ if (m_open) {
+ close(false);
+ }
+
+ store->unregisterFolder(this);
+
+ } else if (m_open) {
+
+ close(false);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void maildirFolder::onStoreDisconnected() {
+
+ m_store.reset();
+}
+
+
+int maildirFolder::getMode() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_mode;
+}
+
+
+const folderAttributes maildirFolder::getAttributes() {
+
+ folderAttributes attribs;
+
+ if (m_path.isEmpty()) {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
+ } else {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS | folderAttributes::TYPE_CONTAINS_MESSAGES);
+ }
+
+ if (m_store.lock()->getFormat()->folderHasSubfolders(m_path)) {
+ attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN); // contains at least one sub-folder
+ }
+
+ return attribs;
+}
+
+
+const folder::path::component maildirFolder::getName() const {
+
+ return m_name;
+}
+
+
+const folder::path maildirFolder::getFullPath() const {
+
+ return m_path;
+}
+
+
+void maildirFolder::open(const int mode, bool /* failIfModeIsNotAvailable */) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is already open");
+ } else if (!exists()) {
+ throw exceptions::illegal_state("Folder does not exist");
+ }
+
+ scanFolder();
+
+ m_open = true;
+ m_mode = mode;
+}
+
+
+void maildirFolder::close(const bool expunge) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (expunge) {
+ this->expunge();
+ }
+
+ m_open = false;
+ m_mode = -1;
+
+ onClose();
+}
+
+
+void maildirFolder::onClose() {
+
+ for (std::vector <maildirMessage*>::iterator it = m_messages.begin() ;
+ it != m_messages.end() ; ++it) {
+
+ (*it)->onFolderClosed();
+ }
+
+ m_messages.clear();
+}
+
+
+void maildirFolder::registerMessage(maildirMessage* msg) {
+
+ m_messages.push_back(msg);
+}
+
+
+void maildirFolder::unregisterMessage(maildirMessage* msg) {
+
+ std::vector <maildirMessage*>::iterator it =
+ std::find(m_messages.begin(), m_messages.end(), msg);
+
+ if (it != m_messages.end()) {
+ m_messages.erase(it);
+ }
+}
+
+
+void maildirFolder::create(const folderAttributes& /* attribs */) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ } else if (exists()) {
+ throw exceptions::illegal_state("Folder already exists");
+ } else if (!store->isValidFolderName(m_name)) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Create directory on file system
+ try {
+ store->getFormat()->createFolder(m_path);
+ } catch (exceptions::filesystem_exception& e) {
+ throw exceptions::command_error("CREATE", "", "File system exception", e);
+ }
+
+ // Notify folder created
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_CREATED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+void maildirFolder::destroy() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ }
+
+ // Delete folder
+ try {
+ store->getFormat()->destroyFolder(m_path);
+ } catch (std::exception&) {
+ // Ignore exception: anyway, we can't recover from this...
+ }
+
+ // Notify folder deleted
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_DELETED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+bool maildirFolder::exists() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ return store->getFormat()->folderExists(m_path);
+}
+
+
+bool maildirFolder::isOpen() const {
+
+ return m_open;
+}
+
+
+void maildirFolder::scanFolder() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ try {
+
+ m_messageCount = 0;
+ m_unreadMessageCount = 0;
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path newDirPath =
+ store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::NEW_DIRECTORY);
+ shared_ptr <utility::file> newDir = fsf->create(newDirPath);
+
+ utility::file::path curDirPath =
+ store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+ shared_ptr <utility::file> curDir = fsf->create(curDirPath);
+
+ // New received messages (new/)
+ shared_ptr <utility::fileIterator> nit = newDir->getFiles();
+ std::vector <utility::file::path::component> newMessageFilenames;
+
+ while (nit->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = nit->nextElement();
+
+ if (maildirUtils::isMessageFile(*file)) {
+ newMessageFilenames.push_back(file->getFullPath().getLastComponent());
+ }
+ }
+
+ // Current messages (cur/)
+ shared_ptr <utility::fileIterator> cit = curDir->getFiles();
+ std::vector <utility::file::path::component> curMessageFilenames;
+
+ while (cit->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = cit->nextElement();
+
+ if (maildirUtils::isMessageFile(*file)) {
+ curMessageFilenames.push_back(file->getFullPath().getLastComponent());
+ }
+ }
+
+ // Update/delete existing messages (found in previous scan)
+ for (size_t i = 0 ; i < m_messageInfos.size() ; ++i) {
+
+ messageInfos& msgInfos = m_messageInfos[i];
+
+ // NOTE: the flags may have changed (eg. moving from 'new' to 'cur'
+ // may imply the 'S' flag) and so the filename. That's why we use
+ // "maildirUtils::messageIdComparator" to compare only the 'unique'
+ // portion of the filename...
+
+ if (msgInfos.type == messageInfos::TYPE_CUR) {
+
+ const std::vector <utility::file::path::component>::iterator pos =
+ std::find_if(
+ curMessageFilenames.begin(),
+ curMessageFilenames.end(),
+ maildirUtils::messageIdComparator(msgInfos.path)
+ );
+
+ // If we cannot find this message in the 'cur' directory,
+ // it means it has been deleted (and expunged).
+ if (pos == curMessageFilenames.end()) {
+
+ msgInfos.type = messageInfos::TYPE_DELETED;
+
+ // Otherwise, update its information.
+ } else {
+
+ msgInfos.path = *pos;
+ curMessageFilenames.erase(pos);
+ }
+ }
+ }
+
+ m_messageInfos.reserve(m_messageInfos.size()
+ + newMessageFilenames.size() + curMessageFilenames.size());
+
+ // Add new messages from 'new': we are responsible to move the files
+ // from the 'new' directory to the 'cur' directory, and append them
+ // to our message list.
+ for (std::vector <utility::file::path::component>::const_iterator
+ it = newMessageFilenames.begin() ; it != newMessageFilenames.end() ; ++it) {
+
+ const utility::file::path::component newFilename =
+ maildirUtils::buildFilename(maildirUtils::extractId(*it), 0);
+
+ // Move messages from 'new' to 'cur'
+ shared_ptr <utility::file> file = fsf->create(newDirPath / *it);
+ file->rename(curDirPath / newFilename);
+
+ // Append to message list
+ messageInfos msgInfos;
+ msgInfos.path = newFilename;
+
+ if (maildirUtils::extractFlags(msgInfos.path) & message::FLAG_DELETED) {
+ msgInfos.type = messageInfos::TYPE_DELETED;
+ } else {
+ msgInfos.type = messageInfos::TYPE_CUR;
+ }
+
+ m_messageInfos.push_back(msgInfos);
+ }
+
+ // Add new messages from 'cur': the files have already been moved
+ // from 'new' to 'cur'. Just append them to our message list.
+ for (std::vector <utility::file::path::component>::const_iterator
+ it = curMessageFilenames.begin() ; it != curMessageFilenames.end() ; ++it) {
+
+ // Append to message list
+ messageInfos msgInfos;
+ msgInfos.path = *it;
+
+ if (maildirUtils::extractFlags(msgInfos.path) & message::FLAG_DELETED) {
+ msgInfos.type = messageInfos::TYPE_DELETED;
+ } else {
+ msgInfos.type = messageInfos::TYPE_CUR;
+ }
+
+ m_messageInfos.push_back(msgInfos);
+ }
+
+ // Update message count
+ size_t unreadMessageCount = 0;
+
+ for (std::vector <messageInfos>::const_iterator
+ it = m_messageInfos.begin() ; it != m_messageInfos.end() ; ++it) {
+
+ if ((maildirUtils::extractFlags((*it).path) & message::FLAG_SEEN) == 0) {
+ ++unreadMessageCount;
+ }
+ }
+
+ m_unreadMessageCount = unreadMessageCount;
+ m_messageCount = static_cast <size_t>(m_messageInfos.size());
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Should not happen...
+ }
+}
+
+
+shared_ptr <message> maildirFolder::getMessage(const size_t num) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (num < 1 || num > m_messageCount) {
+ throw exceptions::message_not_found();
+ }
+
+ return make_shared <maildirMessage>(dynamicCast <maildirFolder>(shared_from_this()), num);
+}
+
+
+std::vector <shared_ptr <message> > maildirFolder::getMessages(const messageSet& msgs) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isNumberSet()) {
+
+ const std::vector <size_t> numbers = maildirUtils::messageSetToNumberList(msgs, m_messageCount);
+
+ std::vector <shared_ptr <message> > messages;
+ shared_ptr <maildirFolder> thisFolder = dynamicCast <maildirFolder>(shared_from_this());
+
+ for (std::vector <size_t>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) {
+
+ if (*it < 1|| *it > m_messageCount) {
+ throw exceptions::message_not_found();
+ }
+
+ messages.push_back(make_shared <maildirMessage>(thisFolder, *it));
+ }
+
+ return messages;
+
+ } else {
+
+ throw exceptions::operation_not_supported();
+ }
+}
+
+
+size_t maildirFolder::getMessageCount() {
+
+ return m_messageCount;
+}
+
+
+shared_ptr <folder> maildirFolder::getFolder(const folder::path::component& name) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return shared_ptr <maildirFolder>(new maildirFolder(m_path / name, store));
+}
+
+
+std::vector <shared_ptr <folder> > maildirFolder::getFolders(const bool recursive) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!isOpen() && !store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ std::vector <shared_ptr <folder> > list;
+
+ listFolders(list, recursive);
+
+ return list;
+}
+
+
+void maildirFolder::listFolders(std::vector <shared_ptr <folder> >& list, const bool recursive) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ try {
+
+ std::vector <folder::path> pathList =
+ store->getFormat()->listFolders(m_path, recursive);
+
+ list.reserve(pathList.size());
+
+ for (std::vector <folder::path>::size_type i = 0, n = pathList.size() ; i < n ; ++i) {
+
+ shared_ptr <maildirFolder> subFolder(
+ new maildirFolder(pathList[i], store)
+ );
+
+ list.push_back(subFolder);
+ }
+
+ } catch (exceptions::filesystem_exception& e) {
+
+ throw exceptions::command_error("LIST", "", "", e);
+ }
+}
+
+
+void maildirFolder::rename(const folder::path& newPath) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (m_path.isEmpty() || newPath.isEmpty()) {
+ throw exceptions::illegal_operation("Cannot rename root folder");
+ } else if (!store->isValidFolderName(newPath.getLastComponent())) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Rename the directory on the file system
+ try {
+ store->getFormat()->renameFolder(m_path, newPath);
+ } catch (vmime::exception& e) {
+ throw exceptions::command_error("RENAME", "", "", e);
+ }
+
+ // Notify folder renamed
+ folder::path oldPath(m_path);
+
+ m_path = newPath;
+ m_name = newPath.getLastComponent();
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, newPath
+ );
+
+ notifyFolder(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == oldPath) {
+
+ (*it)->m_path = newPath;
+ (*it)->m_name = newPath.getLastComponent();
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, newPath
+ );
+
+ (*it)->notifyFolder(event);
+
+ } else if ((*it) != this && oldPath.isParentOf((*it)->getFullPath())) {
+
+ folder::path oldPath((*it)->m_path);
+
+ (*it)->m_path.renameParent(oldPath, newPath);
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, (*it)->m_path
+ );
+
+ (*it)->notifyFolder(event);
+ }
+ }
+}
+
+
+void maildirFolder::deleteMessages(const messageSet& msgs) {
+
+ // Mark messages as deleted
+ setMessageFlags(msgs, message::FLAG_DELETED, message::FLAG_MODE_ADD);
+}
+
+
+void maildirFolder::setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ if (msgs.isNumberSet()) {
+
+ const std::vector <size_t> nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount);
+
+ // Change message flags
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath = store->getFormat()->
+ folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ for (std::vector <size_t>::const_iterator it =
+ nums.begin() ; it != nums.end() ; ++it) {
+
+ const size_t num = *it - 1;
+
+ try {
+
+ const utility::file::path::component path = m_messageInfos[num].path;
+ shared_ptr <utility::file> file = fsf->create(curDirPath / path);
+
+ int newFlags = maildirUtils::extractFlags(path);
+
+ switch (mode) {
+ case message::FLAG_MODE_ADD: newFlags |= flags; break;
+ case message::FLAG_MODE_REMOVE: newFlags &= ~flags; break;
+ default:
+ case message::FLAG_MODE_SET: newFlags = flags; break;
+ }
+
+ const utility::file::path::component newPath =
+ maildirUtils::buildFilename(maildirUtils::extractId(path), newFlags);
+
+ file->rename(curDirPath / newPath);
+
+ if (flags & message::FLAG_DELETED) {
+ m_messageInfos[num].type = messageInfos::TYPE_DELETED;
+ } else {
+ m_messageInfos[num].type = messageInfos::TYPE_CUR;
+ }
+
+ m_messageInfos[num].path = newPath;
+
+ } catch (exceptions::filesystem_exception& e) {
+
+ // Ignore (not important)
+ }
+ }
+
+ // Update local flags
+ switch (mode) {
+
+ case message::FLAG_MODE_ADD: {
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) &&
+ (*it)->m_flags != maildirMessage::FLAG_UNDEFINED) {
+
+ (*it)->m_flags |= flags;
+ }
+ }
+
+ break;
+ }
+ case message::FLAG_MODE_REMOVE: {
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) &&
+ (*it)->m_flags != maildirMessage::FLAG_UNDEFINED) {
+
+ (*it)->m_flags &= ~flags;
+ }
+ }
+
+ break;
+ }
+ default:
+ case message::FLAG_MODE_SET: {
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) &&
+ (*it)->m_flags != maildirMessage::FLAG_UNDEFINED) {
+
+ (*it)->m_flags = flags;
+ }
+ }
+
+ break;
+ }
+
+ }
+
+ // Notify message flags changed
+ shared_ptr <events::messageChangedEvent> event =
+ make_shared <events::messageChangedEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageChangedEvent::TYPE_FLAGS,
+ nums
+ );
+
+ notifyMessageChanged(event);
+
+ // TODO: notify other folders with the same path
+
+ } else {
+
+ throw exceptions::operation_not_supported();
+ }
+}
+
+
+messageSet maildirFolder::addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags,
+ vmime::datetime* date,
+ utility::progressListener* progress
+) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ossAdapter);
+
+ const string& str = oss.str();
+ utility::inputStreamStringAdapter strAdapter(str);
+
+ return addMessage(strAdapter, str.length(), flags, date, progress);
+}
+
+
+messageSet maildirFolder::addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags,
+ vmime::datetime* /* date */,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path tmpDirPath = store->getFormat()->
+ folderPathToFileSystemPath(m_path,maildirFormat::TMP_DIRECTORY);
+ utility::file::path dstDirPath = store->getFormat()->
+ folderPathToFileSystemPath(
+ m_path,
+ flags == message::FLAG_RECENT ?
+ maildirFormat::NEW_DIRECTORY :
+ maildirFormat::CUR_DIRECTORY
+ );
+
+ const utility::file::path::component filename =
+ maildirUtils::buildFilename(maildirUtils::generateId(), ((flags == -1) ? 0 : flags));
+
+ try {
+ shared_ptr <utility::file> tmpDir = fsf->create(tmpDirPath);
+ tmpDir->createDirectory(true);
+ } catch (exceptions::filesystem_exception&) {
+ // Don't throw now, it will fail later...
+ }
+
+ try {
+ shared_ptr <utility::file> curDir = fsf->create(dstDirPath);
+ curDir->createDirectory(true);
+ } catch (exceptions::filesystem_exception&) {
+ // Don't throw now, it will fail later...
+ }
+
+ // Actually add the message
+ copyMessageImpl(tmpDirPath, dstDirPath, filename, is, size, progress);
+
+ // Append the message to the cache list
+ messageInfos msgInfos;
+ msgInfos.path = filename;
+ msgInfos.type = messageInfos::TYPE_CUR;
+
+ m_messageInfos.push_back(msgInfos);
+ m_messageCount++;
+
+ if ((flags == -1) || !(flags & message::FLAG_SEEN)) {
+ m_unreadMessageCount++;
+ }
+
+ // Notification
+ std::vector <size_t> nums;
+ nums.push_back(m_messageCount);
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = m_messageCount;
+ (*it)->m_unreadMessageCount = m_unreadMessageCount;
+
+ (*it)->m_messageInfos.resize(m_messageInfos.size());
+ std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin());
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+
+ return messageSet::empty();
+}
+
+
+void maildirFolder::copyMessageImpl(
+ const utility::file::path& tmpDirPath,
+ const utility::file::path& dstDirPath,
+ const utility::file::path::component& filename,
+ utility::inputStream& is, const size_t size,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> file = fsf->create(tmpDirPath / filename);
+
+ if (progress) {
+ progress->start(size);
+ }
+
+ // First, write the message into 'tmp'...
+ try {
+
+ file->createFile();
+
+ shared_ptr <utility::fileWriter> fw = file->getFileWriter();
+ shared_ptr <utility::outputStream> os = fw->getOutputStream();
+
+ byte_t buffer[65536];
+ size_t total = 0;
+
+ while (!is.eof()) {
+
+ const size_t read = is.read(buffer, sizeof(buffer));
+
+ if (read != 0) {
+ os->write(buffer, read);
+ total += read;
+ }
+
+ if (progress) {
+ progress->progress(total, size);
+ }
+ }
+
+ os->flush();
+
+ } catch (exception& e) {
+
+ if (progress) {
+ progress->stop(size);
+ }
+
+ // Delete temporary file
+ try {
+ shared_ptr <utility::file> file = fsf->create(tmpDirPath / filename);
+ file->remove();
+ } catch (exceptions::filesystem_exception&) {
+ // Ignore
+ }
+
+ throw exceptions::command_error("ADD", "", "", e);
+ }
+
+ // ...then, move it to 'cur'
+ try {
+
+ file->rename(dstDirPath / filename);
+
+ } catch (exception& e) {
+
+ if (progress) {
+ progress->stop(size);
+ }
+
+ // Delete temporary file
+ try {
+
+ file->remove();
+ shared_ptr <utility::file> file = fsf->create(dstDirPath / filename);
+ file->remove();
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Ignore
+ }
+
+ throw exceptions::command_error("ADD", "", "", e);
+ }
+
+ if (progress) {
+ progress->stop(size);
+ }
+}
+
+
+messageSet maildirFolder::copyMessages(const folder::path& dest, const messageSet& msgs) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath =
+ store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ utility::file::path destCurDirPath = store->getFormat()->
+ folderPathToFileSystemPath(dest, maildirFormat::CUR_DIRECTORY);
+ utility::file::path destTmpDirPath = store->getFormat()->
+ folderPathToFileSystemPath(dest, maildirFormat::TMP_DIRECTORY);
+
+ // Create destination directories
+ try {
+
+ shared_ptr <utility::file> destTmpDir = fsf->create(destTmpDirPath);
+ destTmpDir->createDirectory(true);
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Don't throw now, it will fail later...
+ }
+
+ try {
+
+ shared_ptr <utility::file> destCurDir = fsf->create(destCurDirPath);
+ destCurDir->createDirectory(true);
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Don't throw now, it will fail later...
+ }
+
+ // Copy messages
+ const std::vector <size_t> nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount);
+
+ try {
+
+ for (std::vector <size_t>::const_iterator it =
+ nums.begin() ; it != nums.end() ; ++it) {
+
+ const size_t num = *it;
+ const messageInfos& msg = m_messageInfos[num - 1];
+ const int flags = maildirUtils::extractFlags(msg.path);
+
+ const utility::file::path::component filename =
+ maildirUtils::buildFilename(maildirUtils::generateId(), flags);
+
+ shared_ptr <utility::file> file = fsf->create(curDirPath / msg.path);
+ shared_ptr <utility::fileReader> fr = file->getFileReader();
+ shared_ptr <utility::inputStream> is = fr->getInputStream();
+
+ copyMessageImpl(destTmpDirPath, destCurDirPath,
+ filename, *is, file->getLength(), NULL);
+ }
+
+ } catch (exception& e) {
+
+ notifyMessagesCopied(dest);
+ throw exceptions::command_error("COPY", "", "", e);
+ }
+
+ notifyMessagesCopied(dest);
+
+ return messageSet::empty();
+}
+
+
+void maildirFolder::notifyMessagesCopied(const folder::path& dest) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == dest) {
+
+ // We only need to update the first folder we found as calling
+ // status() will notify all the folders with the same path.
+ size_t count, unseen;
+ (*it)->status(count, unseen);
+
+ return;
+ }
+ }
+}
+
+
+void maildirFolder::status(size_t& count, size_t& unseen) {
+
+ count = 0;
+ unseen = 0;
+
+ shared_ptr <folderStatus> status = getStatus();
+
+ count = status->getMessageCount();
+ unseen = status->getUnseenCount();
+
+ m_messageCount = count;
+}
+
+
+shared_ptr <folderStatus> maildirFolder::getStatus() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ const size_t oldCount = m_messageCount;
+
+ scanFolder();
+
+ shared_ptr <maildirFolderStatus> status = make_shared <maildirFolderStatus>();
+
+ status->setMessageCount(m_messageCount);
+ status->setUnseenCount(m_unreadMessageCount);
+
+ // Notify message count changed (new messages)
+ if (m_messageCount > oldCount) {
+
+ std::vector <size_t> nums;
+ nums.reserve(m_messageCount - oldCount);
+
+ for (size_t i = oldCount + 1, j = 0 ; i <= m_messageCount ; ++i, ++j) {
+ nums[j] = i;
+ }
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = m_messageCount;
+ (*it)->m_unreadMessageCount = m_unreadMessageCount;
+
+ (*it)->m_messageInfos.resize(m_messageInfos.size());
+ std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin());
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+ }
+
+ return status;
+}
+
+
+void maildirFolder::expunge() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath = store->getFormat()->
+ folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ std::vector <size_t> nums;
+ size_t unreadCount = 0;
+
+ for (size_t num = 1 ; num <= m_messageCount ; ++num) {
+
+ messageInfos& infos = m_messageInfos[num - 1];
+
+ if (infos.type == messageInfos::TYPE_DELETED) {
+
+ nums.push_back(num);
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if ((*it)->m_num == num) {
+ (*it)->m_expunged = true;
+ } else if ((*it)->m_num > num) {
+ (*it)->m_num--;
+ }
+ }
+
+ if (maildirUtils::extractFlags(infos.path) & message::FLAG_SEEN) {
+ ++unreadCount;
+ }
+
+ // Delete file from file system
+ try {
+ shared_ptr <utility::file> file = fsf->create(curDirPath / infos.path);
+ file->remove();
+ } catch (exceptions::filesystem_exception& e) {
+ // Ignore (not important)
+ }
+ }
+ }
+
+ if (!nums.empty()) {
+
+ for (std::vector <size_t>::size_type i = nums.size() ; i != 0 ; --i) {
+ m_messageInfos.erase(m_messageInfos.begin() + (i - 1));
+ }
+ }
+
+ m_messageCount -= static_cast <size_t>(nums.size());
+ m_unreadMessageCount -= unreadCount;
+
+ // Notify message expunged
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_REMOVED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = m_messageCount;
+ (*it)->m_unreadMessageCount = m_unreadMessageCount;
+
+ (*it)->m_messageInfos.resize(m_messageInfos.size());
+ std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin());
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_REMOVED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+}
+
+
+shared_ptr <folder> maildirFolder::getParent() {
+
+ if (m_path.isEmpty()) {
+ return null;
+ } else {
+ return shared_ptr <maildirFolder>(new maildirFolder(m_path.getParent(), m_store.lock()));
+ }
+}
+
+
+shared_ptr <const store> maildirFolder::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <store> maildirFolder::getStore() {
+
+ return m_store.lock();
+}
+
+
+void maildirFolder::fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msg.empty()) {
+ return;
+ }
+
+ const size_t total = msg.size();
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ shared_ptr <maildirFolder> thisFolder = dynamicCast <maildirFolder>(shared_from_this());
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ dynamicCast <maildirMessage>(*it)->fetch(thisFolder, options);
+
+ if (progress) {
+ progress->progress(++current, total);
+ }
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+}
+
+
+void maildirFolder::fetchMessage(
+ const shared_ptr <message>& msg,
+ const fetchAttributes& options
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ dynamicCast <maildirMessage>(msg)->fetch(
+ dynamicCast <maildirFolder>(shared_from_this()),
+ options
+ );
+}
+
+
+std::vector <shared_ptr <message> > maildirFolder::getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+) {
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ std::vector <shared_ptr <message> > messages = getMessages(msgs);
+ fetchMessages(messages, attribs);
+
+ return messages;
+}
+
+
+int maildirFolder::getFetchCapabilities() const {
+
+ return fetchAttributes::ENVELOPE |
+ fetchAttributes::STRUCTURE |
+ fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FLAGS |
+ fetchAttributes::SIZE |
+ fetchAttributes::FULL_HEADER |
+ fetchAttributes::UID |
+ fetchAttributes::IMPORTANCE;
+}
+
+
+const utility::file::path maildirFolder::getMessageFSPath(const size_t number) const {
+
+ utility::file::path curDirPath = m_store.lock()->getFormat()->
+ folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ return curDirPath / m_messageInfos[number - 1].path;
+}
+
+
+std::vector <size_t> maildirFolder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolder.hpp b/vmime-master/src/vmime/net/maildir/maildirFolder.hpp
new file mode 100644
index 0000000..24f2bf8
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolder.hpp
@@ -0,0 +1,211 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#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 VMIME_EXPORT maildirFolder : public folder {
+
+private:
+
+ friend class maildirStore;
+ friend class maildirMessage;
+
+ maildirFolder(const maildirFolder&) : folder() { }
+ maildirFolder(const folder::path& path, const shared_ptr <maildirStore>& store);
+
+public:
+
+ ~maildirFolder();
+
+
+ int getMode() const;
+
+ const folderAttributes getAttributes();
+
+ 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 folderAttributes& attribs);
+
+ bool exists();
+
+ void destroy();
+
+ bool isOpen() const;
+
+ shared_ptr <message> getMessage(const size_t num);
+ std::vector <shared_ptr <message> > getMessages(const messageSet& msgs);
+
+ size_t getMessageCount();
+
+ shared_ptr <folder> getFolder(const folder::path::component& name);
+ std::vector <shared_ptr <folder> > getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessages(const messageSet& msgs);
+
+ void setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode = message::FLAG_MODE_SET
+ );
+
+ messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet copyMessages(const folder::path& dest, const messageSet& msgs);
+
+ void status(size_t& count, size_t& unseen);
+ shared_ptr <folderStatus> getStatus();
+
+ void expunge();
+
+ shared_ptr <folder> getParent();
+
+ shared_ptr <const store> getStore() const;
+ shared_ptr <store> getStore();
+
+
+ void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress = NULL
+ );
+
+ void fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options);
+
+ std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ );
+
+ int getFetchCapabilities() const;
+
+ std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid);
+
+private:
+
+ void scanFolder();
+
+ void listFolders(std::vector <shared_ptr <folder> >& list, const bool recursive);
+
+ void registerMessage(maildirMessage* msg);
+ void unregisterMessage(maildirMessage* msg);
+
+ const utility::file::path getMessageFSPath(const size_t number) const;
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+ void deleteMessagesImpl(const std::vector <size_t>& nums);
+ void setMessageFlagsImpl(const std::vector <size_t>& nums, const int flags, const int mode);
+
+ void copyMessagesImpl(const folder::path& dest, const std::vector <size_t>& nums);
+ void copyMessageImpl(const utility::file::path& tmpDirPath, const utility::file::path& curDirPath, const utility::file::path::component& filename, utility::inputStream& is, const size_t size, utility::progressListener* progress);
+
+ void notifyMessagesCopied(const folder::path& dest);
+
+
+ weak_ptr <maildirStore> m_store;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ size_t m_unreadMessageCount;
+ size_t 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_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp
new file mode 100644
index 0000000..7438d8c
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFolderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirFolderStatus::maildirFolderStatus()
+ : m_count(0),
+ m_unseen(0) {
+
+}
+
+
+maildirFolderStatus::maildirFolderStatus(const maildirFolderStatus& other)
+ : folderStatus(),
+ m_count(other.m_count),
+ m_unseen(other.m_unseen) {
+
+}
+
+
+size_t maildirFolderStatus::getMessageCount() const {
+
+ return m_count;
+}
+
+
+size_t maildirFolderStatus::getUnseenCount() const {
+
+ return m_unseen;
+}
+
+
+void maildirFolderStatus::setMessageCount(const size_t count) {
+
+ m_count = count;
+}
+
+
+void maildirFolderStatus::setUnseenCount(const size_t unseen) {
+
+ m_unseen = unseen;
+}
+
+
+shared_ptr <folderStatus> maildirFolderStatus::clone() const {
+
+ return make_shared <maildirFolderStatus>(*this);
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp
new file mode 100644
index 0000000..3b69375
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/folderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+/** Holds the status of a Maildir folder.
+ */
+class VMIME_EXPORT maildirFolderStatus : public folderStatus {
+
+public:
+
+ maildirFolderStatus();
+ maildirFolderStatus(const maildirFolderStatus& other);
+
+ // Inherited from folderStatus
+ size_t getMessageCount() const;
+ size_t getUnseenCount() const;
+
+ shared_ptr <folderStatus> clone() const;
+
+
+ void setMessageCount(const size_t count);
+ void setUnseenCount(const size_t unseen);
+
+private:
+
+ size_t m_count;
+ size_t m_unseen;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirFormat.cpp b/vmime-master/src/vmime/net/maildir/maildirFormat.cpp
new file mode 100644
index 0000000..914c078
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFormat.cpp
@@ -0,0 +1,104 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+#include "vmime/net/maildir/maildirStore.hpp"
+
+#include "vmime/net/maildir/format/kmailMaildirFormat.hpp"
+#include "vmime/net/maildir/format/courierMaildirFormat.hpp"
+
+#include "vmime/utility/file.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+const utility::file::path::component maildirFormat::TMP_DIR("tmp", vmime::charset(vmime::charsets::US_ASCII));
+const utility::file::path::component maildirFormat::CUR_DIR("cur", vmime::charset(vmime::charsets::US_ASCII));
+const utility::file::path::component maildirFormat::NEW_DIR("new", vmime::charset(vmime::charsets::US_ASCII));
+
+
+//
+// maildirFormat::context
+//
+
+maildirFormat::context::context(const shared_ptr <maildirStore>& store)
+ : m_store(store) {
+
+}
+
+
+shared_ptr <maildirStore> maildirFormat::context::getStore() {
+
+ return m_store.lock();
+}
+
+
+//
+// maildirFormat
+//
+
+maildirFormat::maildirFormat(const shared_ptr <context>& ctx)
+ : m_context(ctx) {
+
+}
+
+
+shared_ptr <maildirFormat::context> maildirFormat::getContext() const {
+
+ return m_context;
+}
+
+
+// static
+shared_ptr <maildirFormat> maildirFormat::detect(const shared_ptr <maildirStore>& store) {
+
+ shared_ptr <context> ctx = make_shared <context>(store);
+
+ // Try Courier format
+ shared_ptr <maildirFormat> fmt = make_shared <format::courierMaildirFormat>(ctx);
+
+ if (fmt->supports()) {
+ return fmt;
+ }
+
+ // Default is KMail format
+ return make_shared <format::kmailMaildirFormat>(ctx);
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirFormat.hpp b/vmime-master/src/vmime/net/maildir/maildirFormat.hpp
new file mode 100644
index 0000000..9b9e063
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFormat.hpp
@@ -0,0 +1,192 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/folder.hpp"
+
+#include "vmime/utility/file.hpp"
+#include "vmime/utility/path.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirStore;
+
+
+/** Interface for an object capable of reading a specific Maildir format.
+ */
+class VMIME_EXPORT maildirFormat : public object {
+
+public:
+
+ class context : public object {
+
+ public:
+
+ context(const shared_ptr <maildirStore>& store);
+
+ shared_ptr <maildirStore> getStore();
+
+ private:
+
+ weak_ptr <maildirStore> m_store;
+ };
+
+
+ /** Physical directory types. */
+ enum DirectoryType {
+ ROOT_DIRECTORY, /**< Root directory. */
+ NEW_DIRECTORY, /**< Directory containing unread messages. */
+ CUR_DIRECTORY, /**< Directory containing messages that have been seen. */
+ TMP_DIRECTORY, /**< Temporary directory used for reliable delivery. */
+ CONTAINER_DIRECTORY /**< Container for subfolders. */
+ };
+
+ /** Return the name of this Maildir format.
+ *
+ * @return format name
+ */
+ virtual const string getName() const = 0;
+
+ /** Create the specified folder.
+ *
+ * @param path virtual path of the folder
+ * @throw exceptions::filesystem_exception, invalid_folder_name
+ */
+ virtual void createFolder(const folder::path& path) = 0;
+
+ /** Destroy the specified folder.
+ *
+ * @param path virtual path of the folder
+ * @throw exceptions::filesystem_exception
+ */
+ virtual void destroyFolder(const folder::path& path) = 0;
+
+ /** Rename the specified folder.
+ *
+ * @param oldPath old virtual path of the folder
+ * @param newPath new virtual path of the folder
+ * @throw exceptions::filesystem_exception
+ */
+ virtual void renameFolder(const folder::path& oldPath, const folder::path& newPath) = 0;
+
+ /** Test whether the specified folder exists.
+ *
+ * @param path virtual path of the folder
+ * @return true if the folder exists, false otherwise
+ */
+ virtual bool folderExists(const folder::path& path) const = 0;
+
+ /** Test whether the specified folder has subfolders.
+ *
+ * @param path virtual path of the folder
+ * @return true if the folder has at least one subfolder,
+ * false otherwise
+ */
+ virtual bool folderHasSubfolders(const folder::path& path) const = 0;
+
+ /** Returns the directory which represents the specified
+ * folder on the file system.
+ *
+ * @param path virtual path of the folder
+ * @param type type of directory to return
+ * @return corresponding directory on the file system
+ */
+ virtual const utility::file::path folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+ ) const = 0;
+
+ /** List subfolders in the specified folder.
+ *
+ * @param root root folder in which to start the search
+ * @param recursive if set to true, all the descendant are
+ * returned; if set to false, only direct children are returned.
+ * @return list of subfolders
+ */
+ virtual const std::vector <folder::path> listFolders(
+ const folder::path& root,
+ const bool recursive
+ ) const = 0;
+
+
+ /** Try to detect the format of the specified Maildir store.
+ * If the format cannot be detected, a compatible implementation
+ * will be returned.
+ *
+ * @param store of which to detect format
+ * @return a Maildir format implementation for the specified store
+ */
+ static shared_ptr <maildirFormat> detect(const shared_ptr <maildirStore>& store);
+
+protected:
+
+ static const utility::file::path::component TMP_DIR; /**< Ensure reliable delivery (not to be listed). */
+ static const utility::file::path::component CUR_DIR; /**< No longer new messages. */
+ static const utility::file::path::component NEW_DIR; /**< Unread messages. */
+
+
+ maildirFormat(const shared_ptr <context>& ctx);
+
+
+ /** Returns the current context.
+ *
+ * @return current context
+ */
+ shared_ptr <context> getContext() const;
+
+ /** Quick checks whether this implementation can read the Maildir
+ * format in the specified directory.
+ *
+ * @return true if the implementation supports the specified
+ * Maildir, or false otherwise
+ */
+ virtual bool supports() const = 0;
+
+private:
+
+ shared_ptr <context> m_context;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessage.cpp b/vmime-master/src/vmime/net/maildir/maildirMessage.cpp
new file mode 100644
index 0000000..ae99c59
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessage.cpp
@@ -0,0 +1,410 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirMessage.hpp"
+#include "vmime/net/maildir/maildirMessagePart.hpp"
+#include "vmime/net/maildir/maildirMessageStructure.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/platform.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirMessage::maildirMessage(const shared_ptr <maildirFolder>& folder, const size_t num)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1),
+ m_flags(FLAG_UNDEFINED),
+ m_expunged(false),
+ m_structure(null) {
+
+ folder->registerMessage(this);
+}
+
+
+maildirMessage::~maildirMessage() {
+
+ try {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ if (folder) {
+ folder->unregisterMessage(this);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void maildirMessage::onFolderClosed() {
+
+ m_folder.reset();
+}
+
+
+size_t maildirMessage::getNumber() const {
+
+ return m_num;
+}
+
+
+const message::uid maildirMessage::getUID() const {
+
+ return m_uid;
+}
+
+
+size_t maildirMessage::getSize() const {
+
+ if (m_size == static_cast <size_t>(-1)) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_size;
+}
+
+
+bool maildirMessage::isExpunged() const {
+
+ return m_expunged;
+}
+
+
+shared_ptr <const messageStructure> maildirMessage::getStructure() const {
+
+ if (!m_structure) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <messageStructure> maildirMessage::getStructure() {
+
+ if (!m_structure) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <const header> maildirMessage::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_header;
+}
+
+
+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) {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode);
+}
+
+
+void maildirMessage::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ extractImpl(os, progress, 0, m_size, start, length, peek);
+}
+
+
+void maildirMessage::extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ shared_ptr <const maildirMessagePart> mp = dynamicCast <const maildirMessagePart>(p);
+
+ extractImpl(
+ os, progress, mp->getBodyParsedOffset(), mp->getBodyParsedLength(),
+ start, length, peek
+ );
+}
+
+
+void maildirMessage::extractImpl(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const size_t partialStart,
+ const size_t partialLength,
+ const bool /* peek */
+) const {
+
+ shared_ptr <const maildirFolder> folder = m_folder.lock();
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path path = folder->getMessageFSPath(m_num);
+ shared_ptr <utility::file> file = fsf->create(path);
+
+ shared_ptr <utility::fileReader> reader = file->getFileReader();
+ shared_ptr <utility::inputStream> is = reader->getInputStream();
+
+ is->skip(start + partialStart);
+
+ byte_t buffer[8192];
+ size_t remaining =
+ (partialLength == static_cast <size_t>(-1)
+ ? length
+ : std::min(partialLength, length)
+ );
+
+ const size_t total = remaining;
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ while (!is->eof() && remaining > 0) {
+
+ const size_t 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(const shared_ptr <messagePart>& p) {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ shared_ptr <maildirMessagePart> mp = dynamicCast <maildirMessagePart>(p);
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path path = folder->getMessageFSPath(m_num);
+ shared_ptr <utility::file> file = fsf->create(path);
+
+ shared_ptr <utility::fileReader> reader = file->getFileReader();
+ shared_ptr <utility::inputStream> is = reader->getInputStream();
+
+ is->skip(mp->getHeaderParsedOffset());
+
+ byte_t buffer[1024];
+ size_t remaining = mp->getHeaderParsedLength();
+
+ string contents;
+ contents.reserve(remaining);
+
+ while (!is->eof() && remaining > 0) {
+
+ const size_t read = is->read(buffer, std::min(remaining, sizeof(buffer)));
+
+ remaining -= read;
+
+ vmime::utility::stringUtils::appendBytesToString(contents, buffer, read);
+ }
+
+ mp->getOrCreateHeader().parse(contents);
+}
+
+
+void maildirMessage::fetch(const shared_ptr <maildirFolder>& msgFolder, const fetchAttributes& options) {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ if (folder != msgFolder) {
+ throw exceptions::folder_not_found();
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path path = folder->getMessageFSPath(m_num);
+ shared_ptr <utility::file> file = fsf->create(path);
+
+ if (options.has(fetchAttributes::FLAGS)) {
+ m_flags = maildirUtils::extractFlags(path.getLastComponent());
+ }
+
+ if (options.has(fetchAttributes::SIZE)) {
+ m_size = file->getLength();
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+ m_uid = maildirUtils::extractId(path.getLastComponent()).getBuffer();
+ }
+
+ if (options.has(fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FULL_HEADER | fetchAttributes::STRUCTURE |
+ fetchAttributes::IMPORTANCE)) {
+
+ string contents;
+
+ shared_ptr <utility::fileReader> reader = file->getFileReader();
+ shared_ptr <utility::inputStream> is = reader->getInputStream();
+
+ // Need whole message contents for structure
+ if (options.has(fetchAttributes::STRUCTURE)) {
+
+ byte_t buffer[16384];
+
+ contents.reserve(file->getLength());
+
+ while (!is->eof()) {
+ const size_t read = is->read(buffer, sizeof(buffer));
+ vmime::utility::stringUtils::appendBytesToString(contents, buffer, read);
+ }
+
+ // Need only header
+ } else {
+
+ byte_t buffer[1024];
+
+ contents.reserve(4096);
+
+ while (!is->eof()) {
+
+ const size_t read = is->read(buffer, sizeof(buffer));
+ vmime::utility::stringUtils::appendBytesToString(contents, buffer, read);
+
+ const size_t sep1 = contents.rfind("\r\n\r\n");
+ const size_t 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.has(fetchAttributes::STRUCTURE)) {
+ m_structure = make_shared <maildirMessageStructure>(shared_ptr <maildirMessagePart>(), msg);
+ }
+
+ // Extract some header fields or whole header
+ if (options.has(fetchAttributes::ENVELOPE |
+ fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FULL_HEADER |
+ fetchAttributes::IMPORTANCE)) {
+
+ getOrCreateHeader()->copyFrom(*(msg.getHeader()));
+ }
+ }
+}
+
+
+shared_ptr <header> maildirMessage::getOrCreateHeader() {
+
+ if (m_header) {
+ return m_header;
+ } else {
+ return (m_header = make_shared <header>());
+ }
+}
+
+
+shared_ptr <vmime::message> maildirMessage::getParsedMessage() {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter os(oss);
+
+ extract(os);
+
+ shared_ptr <vmime::message> msg = make_shared <vmime::message>();
+ msg->parse(oss.str());
+
+ return msg;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessage.hpp b/vmime-master/src/vmime/net/maildir/maildirMessage.hpp
new file mode 100644
index 0000000..8cd0aac
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessage.hpp
@@ -0,0 +1,137 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirFolder;
+
+
+/** maildir message implementation.
+ */
+class VMIME_EXPORT maildirMessage : public message {
+
+ friend class maildirFolder;
+
+ maildirMessage(const maildirMessage&) : message() { }
+
+public:
+
+ maildirMessage(const shared_ptr <maildirFolder>& folder, const size_t num);
+
+ ~maildirMessage();
+
+
+ size_t getNumber() const;
+
+ const uid getUID() const;
+
+ size_t getSize() const;
+
+ bool isExpunged() const;
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const header> getHeader() const;
+
+ int getFlags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void fetchPartHeader(const shared_ptr <messagePart>& p);
+
+ shared_ptr <vmime::message> getParsedMessage();
+
+private:
+
+ void fetch(const shared_ptr <maildirFolder>& folder, const fetchAttributes& options);
+
+ void onFolderClosed();
+
+ shared_ptr <header> getOrCreateHeader();
+
+ void extractImpl(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const size_t partialStart,
+ const size_t partialLength,
+ const bool peek
+ ) const;
+
+
+ weak_ptr <maildirFolder> m_folder;
+
+ size_t m_num;
+ size_t m_size;
+ int m_flags;
+ bool m_expunged;
+ uid m_uid;
+
+ shared_ptr <header> m_header;
+ shared_ptr <messageStructure> m_structure;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp b/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp
new file mode 100644
index 0000000..7448d7e
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp
@@ -0,0 +1,178 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirMessagePart.hpp"
+#include "vmime/net/maildir/maildirMessageStructure.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirMessagePart::maildirMessagePart(
+ const shared_ptr <maildirMessagePart>& parent,
+ const size_t number,
+ const bodyPart& part
+)
+ : m_parent(parent),
+ m_header(null),
+ m_number(number) {
+
+ 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();
+
+ auto cdispField = part.getHeader()->ContentDisposition();
+ if (cdispField) {
+ m_dispType = dynamic_cast <const contentDisposition&>(*cdispField->getValue());
+ }
+}
+
+
+maildirMessagePart::~maildirMessagePart() {
+
+}
+
+
+void maildirMessagePart::initStructure(const bodyPart& part) {
+
+ if (part.getBody()->getPartList().size() == 0) {
+
+ m_structure = null;
+
+ } else {
+
+ m_structure = make_shared <maildirMessageStructure>(
+ dynamicCast <maildirMessagePart>(shared_from_this()), part.getBody()->getPartList()
+ );
+ }
+}
+
+
+shared_ptr <const messageStructure> maildirMessagePart::getStructure() const {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return maildirMessageStructure::emptyStructure();
+ }
+}
+
+
+shared_ptr <messageStructure> maildirMessagePart::getStructure() {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return maildirMessageStructure::emptyStructure();
+ }
+}
+
+
+const mediaType& maildirMessagePart::getType() const {
+
+ return m_mediaType;
+}
+
+
+const contentDisposition &maildirMessagePart::getDisposition() const {
+
+ return m_dispType;
+}
+
+
+size_t maildirMessagePart::getSize() const {
+
+ return m_size;
+}
+
+
+size_t maildirMessagePart::getNumber() const {
+
+ return m_number;
+}
+
+
+shared_ptr <const header> maildirMessagePart::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ } else {
+ return m_header;
+ }
+}
+
+
+header& maildirMessagePart::getOrCreateHeader() {
+
+ if (m_header) {
+ return *m_header;
+ } else {
+ return *(m_header = make_shared <header>());
+ }
+}
+
+
+size_t maildirMessagePart::getHeaderParsedOffset() const {
+
+ return m_headerParsedOffset;
+}
+
+
+size_t maildirMessagePart::getHeaderParsedLength() const {
+
+ return m_headerParsedLength;
+}
+
+
+size_t maildirMessagePart::getBodyParsedOffset() const {
+
+ return m_bodyParsedOffset;
+}
+
+
+size_t maildirMessagePart::getBodyParsedLength() const {
+
+ return m_bodyParsedLength;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp b/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp
new file mode 100644
index 0000000..5ecc739
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp
@@ -0,0 +1,106 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/message.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirMessageStructure;
+
+
+class maildirMessagePart : public messagePart
+{
+public:
+
+ maildirMessagePart(
+ const shared_ptr <maildirMessagePart>& parent,
+ const size_t number,
+ const bodyPart& part
+ );
+
+ ~maildirMessagePart();
+
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ weak_ptr <const maildirMessagePart> getParent() const { return (m_parent); }
+
+ const mediaType& getType() const;
+ const contentDisposition &getDisposition() const;
+ size_t getSize() const;
+ size_t getNumber() const;
+
+ shared_ptr <const header> getHeader() const;
+
+ header& getOrCreateHeader();
+
+ size_t getHeaderParsedOffset() const;
+ size_t getHeaderParsedLength() const;
+
+ size_t getBodyParsedOffset() const;
+ size_t getBodyParsedLength() const;
+
+ void initStructure(const bodyPart& part);
+
+private:
+
+ shared_ptr <maildirMessageStructure> m_structure;
+ weak_ptr <maildirMessagePart> m_parent;
+ shared_ptr <header> m_header;
+
+ size_t m_number;
+ size_t m_size;
+ mediaType m_mediaType;
+ contentDisposition m_dispType;
+
+ size_t m_headerParsedOffset;
+ size_t m_headerParsedLength;
+
+ size_t m_bodyParsedOffset;
+ size_t m_bodyParsedLength;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp
new file mode 100644
index 0000000..1e2f2cc
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp
@@ -0,0 +1,104 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirMessageStructure.hpp"
+#include "vmime/net/maildir/maildirMessagePart.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+shared_ptr <maildirMessageStructure> maildirMessageStructure::m_emptyStructure = make_shared <maildirMessageStructure>();
+
+
+maildirMessageStructure::maildirMessageStructure()
+{
+}
+
+
+maildirMessageStructure::maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const bodyPart& part
+) {
+
+ shared_ptr <maildirMessagePart> mpart = make_shared <maildirMessagePart>(parent, 0, part);
+ mpart->initStructure(part);
+
+ m_parts.push_back(mpart);
+}
+
+
+maildirMessageStructure::maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const std::vector <shared_ptr <const vmime::bodyPart> >& list
+) {
+
+ for (size_t i = 0 ; i < list.size() ; ++i) {
+
+ shared_ptr <maildirMessagePart> mpart = make_shared <maildirMessagePart>(parent, i, *list[i]);
+ mpart->initStructure(*list[i]);
+
+ m_parts.push_back(mpart);
+ }
+}
+
+
+shared_ptr <const messagePart> maildirMessageStructure::getPartAt(const size_t x) const {
+
+ return m_parts[x];
+}
+
+
+shared_ptr <messagePart> maildirMessageStructure::getPartAt(const size_t x) {
+
+ return m_parts[x];
+}
+
+
+size_t maildirMessageStructure::getPartCount() const {
+
+ return m_parts.size();
+}
+
+
+// static
+shared_ptr <maildirMessageStructure> maildirMessageStructure::emptyStructure() {
+
+ return m_emptyStructure;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp
new file mode 100644
index 0000000..1a20ea4
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/message.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirMessagePart;
+
+
+class maildirMessageStructure : public messageStructure {
+
+public:
+
+ maildirMessageStructure();
+ maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const bodyPart& part
+ );
+ maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const std::vector <shared_ptr <const vmime::bodyPart> >& list
+ );
+
+
+ shared_ptr <const messagePart> getPartAt(const size_t x) const;
+ shared_ptr <messagePart> getPartAt(const size_t x);
+
+ size_t getPartCount() const;
+
+ static shared_ptr <maildirMessageStructure> emptyStructure();
+
+private:
+
+ static shared_ptr <maildirMessageStructure> m_emptyStructure;
+
+ std::vector <shared_ptr <maildirMessagePart> > m_parts;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp
new file mode 100644
index 0000000..f9d92d3
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirServiceInfos::maildirServiceInfos() {
+
+}
+
+
+const string maildirServiceInfos::getPropertyPrefix() const {
+
+ return "store.maildir.";
+}
+
+
+const maildirServiceInfos::props& maildirServiceInfos::getProperties() const {
+
+ static props maildirProps = {
+ property(serviceInfos::property::SERVER_ROOTPATH, serviceInfos::property::FLAG_REQUIRED)
+ };
+
+ return maildirProps;
+}
+
+
+const std::vector <serviceInfos::property> maildirServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ list.push_back(p.PROPERTY_SERVER_ROOTPATH);
+
+ return list;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp
new file mode 100644
index 0000000..827a7d7
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+/** Information about maildir service.
+ */
+class VMIME_EXPORT maildirServiceInfos : public serviceInfos {
+
+public:
+
+ maildirServiceInfos();
+
+ struct props {
+ serviceInfos::property PROPERTY_SERVER_ROOTPATH;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirStore.cpp b/vmime-master/src/vmime/net/maildir/maildirStore.cpp
new file mode 100644
index 0000000..a994f45
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirStore.cpp
@@ -0,0 +1,294 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirStore.hpp"
+
+#include "vmime/net/maildir/maildirFolder.hpp"
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (getInfos().hasProperty(getSession(), \
+ dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirStore::maildirStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : store(sess, getInfosInstance(), auth),
+ m_connected(false) {
+
+}
+
+
+maildirStore::~maildirStore() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string maildirStore::getProtocolName() const {
+
+ return "maildir";
+}
+
+
+shared_ptr <folder> maildirStore::getRootFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <maildirFolder>(
+ new maildirFolder(
+ folder::path(),
+ dynamicCast <maildirStore>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> maildirStore::getDefaultFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <maildirFolder>(
+ new maildirFolder(
+ folder::path::component("inbox"),
+ dynamicCast <maildirStore>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> maildirStore::getFolder(const folder::path& path) {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <maildirFolder>(
+ new maildirFolder(
+ path,
+ dynamicCast <maildirStore>(shared_from_this())
+ )
+ );
+}
+
+
+bool maildirStore::isValidFolderName(const folder::path::component& name) const {
+
+ if (!platform::getHandler()->getFileSystemFactory()->isValidPathComponent(name)) {
+ return false;
+ }
+
+ const string& buf = name.getBuffer();
+
+ // Name cannot start/end with spaces
+ if (utility::stringUtils::trim(buf) != buf) {
+ return false;
+ }
+
+ // Name cannot start with '.'
+ const size_t length = buf.length();
+ size_t pos = 0;
+
+ while ((pos < length) && (buf[pos] == '.')) {
+ ++pos;
+ }
+
+ return (pos == 0);
+}
+
+
+void maildirStore::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ // Get root directory
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ m_fsPath = fsf->stringToPath(GET_PROPERTY(string, PROPERTY_SERVER_ROOTPATH));
+
+ shared_ptr <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_format = maildirFormat::detect(dynamicCast <maildirStore>(shared_from_this()));
+
+ m_connected = true;
+}
+
+
+bool maildirStore::isConnected() const {
+
+ return m_connected;
+}
+
+
+bool maildirStore::isSecuredConnection() const {
+
+ return false;
+}
+
+
+shared_ptr <connectionInfos> maildirStore::getConnectionInfos() const {
+
+ return make_shared <defaultConnectionInfos>("localhost", static_cast <port_t>(0));
+}
+
+
+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.
+}
+
+
+shared_ptr <maildirFormat> maildirStore::getFormat() {
+
+ return m_format;
+}
+
+
+shared_ptr <const maildirFormat> maildirStore::getFormat() const {
+
+ return m_format;
+}
+
+
+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;
+}
+
+
+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
+
+maildirServiceInfos maildirStore::sm_infos;
+
+
+const serviceInfos& maildirStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& maildirStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirStore.hpp b/vmime-master/src/vmime/net/maildir/maildirStore.hpp
new file mode 100644
index 0000000..13255c0
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirStore.hpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/store.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+#include "vmime/net/maildir/maildirServiceInfos.hpp"
+
+#include "vmime/utility/file.hpp"
+
+#include <ostream>
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirFolder;
+
+
+/** maildir store service.
+ */
+class VMIME_EXPORT maildirStore : public store {
+
+ friend class maildirFolder;
+
+public:
+
+ maildirStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~maildirStore();
+
+ const string getProtocolName() const;
+
+ shared_ptr <folder> getDefaultFolder();
+ shared_ptr <folder> getRootFolder();
+ shared_ptr <folder> getFolder(const folder::path& path);
+
+ bool isValidFolderName(const folder::path::component& name) const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ const utility::path& getFileSystemPath() const;
+
+ int getCapabilities() const;
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ shared_ptr <maildirFormat> getFormat();
+ shared_ptr <const maildirFormat> getFormat() const;
+
+private:
+
+ void registerFolder(maildirFolder* folder);
+ void unregisterFolder(maildirFolder* folder);
+
+
+ std::list <maildirFolder*> m_folders;
+
+ shared_ptr <maildirFormat> m_format;
+
+ bool m_connected;
+
+ utility::path m_fsPath;
+
+
+ // Service infos
+ static maildirServiceInfos sm_infos;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirUtils.cpp b/vmime-master/src/vmime/net/maildir/maildirUtils.cpp
new file mode 100644
index 0000000..9942e56
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirUtils.cpp
@@ -0,0 +1,288 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirUtils.hpp"
+#include "vmime/net/maildir/maildirStore.hpp"
+
+#include "vmime/utility/random.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+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;
+}
+
+
+// NOTE ABOUT ID/FLAGS SEPARATOR
+// -----------------------------
+// In the maildir specification, the character ':' is used to separate
+// the unique identifier and the message flags.
+//
+// On Windows (and particularly FAT file systems), ':' is not allowed
+// in a filename, so we use a dash ('-') instead. This is the solution
+// used by Mutt/Win32, so we also use it here.
+//
+// To be compatible between implementations, we check for both
+// characters when reading file names.
+
+
+const utility::file::path::component maildirUtils::extractId(
+ const utility::file::path::component& filename
+) {
+
+ size_t sep = filename.getBuffer().rfind(':'); // try colon
+
+ if (sep == string::npos) {
+ sep = filename.getBuffer().rfind('-'); // try dash (Windows)
+ if (sep == string::npos) return (filename);
+ }
+
+ return utility::path::component(
+ string(filename.getBuffer().begin(), filename.getBuffer().begin() + sep)
+ );
+}
+
+
+int maildirUtils::extractFlags(const utility::file::path::component& comp) {
+
+ size_t sep = comp.getBuffer().rfind(':'); // try colon
+
+ if (sep == string::npos) {
+ sep = comp.getBuffer().rfind('-'); // try dash (Windows)
+ if (sep == string::npos) return 0;
+ }
+
+ const string flagsString(comp.getBuffer().begin() + sep + 1, comp.getBuffer().end());
+ const size_t count = flagsString.length();
+
+ int flags = 0;
+
+ for (size_t 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;
+ case 'D': case 'd': flags |= message::FLAG_DRAFT; 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";
+ if (flags & message::FLAG_DRAFT) str += "D";
+
+ return utility::file::path::component(str);
+}
+
+
+const utility::file::path::component maildirUtils::buildFilename(
+ const utility::file::path::component& id,
+ const int flags
+) {
+
+ if (flags == message::FLAG_RECENT) {
+ return id;
+ } else {
+ return buildFilename(id, buildFlags(flags));
+ }
+}
+
+
+const utility::file::path::component maildirUtils::buildFilename(
+ const utility::file::path::component& id,
+ const utility::file::path::component& flags
+) {
+
+#if VMIME_PLATFORM_IS_WINDOWS
+ static const char DELIMITER[] = "-";
+#else
+ static const char DELIMITER[] = ":";
+#endif
+
+ return utility::path::component(id.getBuffer() + DELIMITER + flags.getBuffer());
+}
+
+
+const utility::file::path::component maildirUtils::generateId() {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ oss << utility::random::getTime();
+ oss << ".";
+ oss << utility::random::getProcess();
+ oss << ".";
+ oss << utility::random::getString(6);
+ oss << ".";
+ oss << platform::getHandler()->getHostName();
+
+ return utility::file::path::component(oss.str());
+}
+
+
+void maildirUtils::recursiveFSDelete(const shared_ptr <utility::file>& dir) {
+
+ shared_ptr <utility::fileIterator> files = dir->getFiles();
+
+ // First, delete files and subdirectories in this directory
+ while (files->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = files->nextElement();
+
+ if (file->isDirectory()) {
+
+ maildirUtils::recursiveFSDelete(file);
+
+ } else {
+
+ try {
+ file->remove();
+ } catch (exceptions::filesystem_exception&) {
+ // Ignore
+ }
+ }
+ }
+
+ // Then, delete this (empty) directory
+ try {
+ dir->remove();
+ } catch (exceptions::filesystem_exception&) {
+ // Ignore
+ }
+}
+
+
+
+class maildirMessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ maildirMessageSetEnumerator(const size_t msgCount)
+ : m_msgCount(msgCount) {
+
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ size_t last = range.getLast();
+ if (last == size_t(-1)) last = m_msgCount;
+
+ for (size_t i = range.getFirst() ; i <= last ; ++i) {
+ list.push_back(i);
+ }
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) {
+
+ // Not supported
+ }
+
+public:
+
+ std::vector <size_t> list;
+
+private:
+
+ size_t m_msgCount;
+};
+
+
+// static
+const std::vector <size_t> maildirUtils::messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+) {
+
+ maildirMessageSetEnumerator en(msgCount);
+ msgs.enumerate(en);
+
+ return en.list;
+}
+
+
+
+//
+// messageIdComparator
+//
+
+maildirUtils::messageIdComparator::messageIdComparator(
+ const utility::file::path::component& comp
+)
+ : m_comp(maildirUtils::extractId(comp)) {
+
+}
+
+
+bool maildirUtils::messageIdComparator::operator()(
+ const utility::file::path::component& other
+) const {
+
+ return m_comp == maildirUtils::extractId(other);
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirUtils.hpp b/vmime-master/src/vmime/net/maildir/maildirUtils.hpp
new file mode 100644
index 0000000..94ab998
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirUtils.hpp
@@ -0,0 +1,160 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/utility/file.hpp"
+#include "vmime/utility/path.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirStore;
+
+
+/** Miscellaneous helpers functions for maildir messaging system.
+ */
+class VMIME_EXPORT 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);
+
+ bool operator()(const utility::file::path::component& other) const;
+
+ private:
+
+ const utility::file::path::component m_comp;
+ };
+
+ /** 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 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 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();
+
+ /** Recursively delete a directory on the file system.
+ *
+ * @param dir directory to delete
+ */
+ static void recursiveFSDelete(const shared_ptr <utility::file>& dir);
+
+ /** Returns a list of message numbers given a message set.
+ *
+ * @param msgs message set
+ * @param msgCount number of messages in folder
+ * @return list of message numbers
+ */
+ static const std::vector <size_t> messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+ );
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/message.cpp b/vmime-master/src/vmime/net/message.cpp
new file mode 100644
index 0000000..2d6f995
--- /dev/null
+++ b/vmime-master/src/vmime/net/message.cpp
@@ -0,0 +1,155 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/message.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+
+
+string messagePart::getName() const
+{
+ return {};
+}
+
+shared_ptr <const messagePart> messagePart::getPartAt(const size_t pos) const {
+
+ return getStructure()->getPartAt(pos);
+}
+
+
+shared_ptr <messagePart> messagePart::getPartAt(const size_t pos) {
+
+ return getStructure()->getPartAt(pos);
+}
+
+
+size_t messagePart::getPartCount() const {
+
+ return getStructure()->getPartCount();
+}
+
+
+
+// message::uid
+
+
+message::uid::uid() {
+
+}
+
+
+message::uid::uid(const string& uid)
+ : m_str(uid) {
+
+}
+
+
+message::uid::uid(const unsigned long uid) {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+ oss << uid;
+
+ m_str = oss.str();
+}
+
+
+message::uid::uid(const char* uid)
+ : m_str(uid) {
+
+}
+
+
+message::uid::uid(const uid& other) {
+
+ m_str = other.m_str;
+}
+
+
+message::uid& message::uid::operator=(const uid& other) {
+
+ m_str = other.m_str;
+ return *this;
+}
+
+
+message::uid& message::uid::operator=(const string& uid) {
+
+ m_str = uid;
+ return *this;
+}
+
+
+message::uid& message::uid::operator=(const unsigned long uid) {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+ oss << uid;
+
+ m_str = oss.str();
+
+ return *this;
+}
+
+
+message::uid::operator string() const {
+
+ return m_str;
+}
+
+
+bool message::uid::empty() const {
+
+ return m_str.empty();
+}
+
+
+bool message::uid::operator==(const uid& other) const {
+
+ return m_str == other.m_str;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const message::uid& uid) {
+
+ os << static_cast <string>(uid);
+ return os;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/message.hpp b/vmime-master/src/vmime/net/message.hpp
new file mode 100644
index 0000000..8679879
--- /dev/null
+++ b/vmime-master/src/vmime/net/message.hpp
@@ -0,0 +1,369 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MESSAGE_HPP_INCLUDED
+#define VMIME_NET_MESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/header.hpp"
+#include "vmime/mediaType.hpp"
+#include "vmime/contentDisposition.hpp"
+
+#include "vmime/utility/progressListener.hpp"
+#include "vmime/utility/stream.hpp"
+
+#include "vmime/message.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class messageStructure;
+
+
+/** A MIME part in a message.
+ */
+class VMIME_EXPORT messagePart : public object, public enable_shared_from_this <messagePart> {
+
+protected:
+
+ messagePart() { }
+ messagePart(const messagePart&);
+
+ virtual ~messagePart() { }
+
+public:
+
+ /** Return the structure of this part.
+ *
+ * @return structure of the part
+ */
+ virtual shared_ptr <const messageStructure> getStructure() const = 0;
+
+ /** Return the structure of this part.
+ *
+ * @return structure of the part
+ */
+ virtual shared_ptr <messageStructure> getStructure() = 0;
+
+ /** Return the header section for this part (you must fetch header
+ * before using this function: see message::fetchPartHeader).
+ *
+ * @return header section
+ */
+ virtual shared_ptr <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 disposition type of the content in this part.
+ *
+ * @return content disposition type
+ */
+ virtual const contentDisposition &getDisposition() const = 0;
+
+ /** Return the size of this part.
+ *
+ * @return size of the part (in bytes)
+ */
+ virtual size_t getSize() const = 0;
+
+ /** Return the part sequence number (index).
+ * The first part is at index zero.
+ *
+ * @return part number
+ */
+ virtual size_t getNumber() const = 0;
+
+ /** Return the name of this part. In particular, this corresponds to
+ * the attachment file name for attachment parts.
+ *
+ * The part name may be empty if the part does not advertise it or
+ * if the underlying protocol does not support it.
+ *
+ * @return part name
+ */
+ virtual string getName() const;
+
+ /** Return the sub-part at the specified position (zero is the
+ * first part).
+ *
+ * @param pos index of the sub-part
+ * @return sub-part at position 'pos'
+ */
+ shared_ptr <const messagePart> getPartAt(const size_t pos) const;
+
+ /** Return the sub-part at the specified position (zero is the
+ * first part).
+ *
+ * @param pos index of the sub-part
+ * @return sub-part at position 'pos'
+ */
+ shared_ptr <messagePart> getPartAt(const size_t pos);
+
+ /** Return the number of sub-parts in this part.
+ *
+ * @return number of sub-parts
+ */
+ size_t getPartCount() const;
+};
+
+
+/** Structure of a MIME part/message.
+ */
+class VMIME_EXPORT messageStructure : public object, public enable_shared_from_this <messageStructure> {
+
+protected:
+
+ messageStructure() { }
+ messageStructure(const messageStructure&);
+
+public:
+
+ virtual ~messageStructure() { }
+
+ /** Return the part at the specified position (first
+ * part is at position 0).
+ *
+ * @param pos position
+ * @return part at position 'pos'
+ */
+ virtual shared_ptr <const messagePart> getPartAt(const size_t pos) const = 0;
+
+ /** Return the part at the specified position (first
+ * part is at position 0).
+ *
+ * @param pos position
+ * @return part at position 'pos'
+ */
+ virtual shared_ptr <messagePart> getPartAt(const size_t pos) = 0;
+
+ /** Return the number of parts in this part.
+ *
+ * @return number of parts
+ */
+ virtual size_t getPartCount() const = 0;
+};
+
+
+/** Abstract representation of a message in a store/transport service.
+ */
+class VMIME_EXPORT message : public object, public enable_shared_from_this <message> {
+
+protected:
+
+ message() { }
+ message(const message&);
+
+ enum PrivateConstants {
+ FLAG_UNDEFINED = 9999 /**< Used internally to indicate flags have not
+ been initialized yet. */
+ };
+
+public:
+
+ /** The type for an unique message identifier.
+ */
+ class VMIME_EXPORT uid {
+
+ public:
+
+ uid();
+ uid(const string& uid);
+ uid(const unsigned long uid);
+ uid(const char* uid);
+ uid(const uid& other);
+
+ uid& operator=(const uid& other);
+ uid& operator=(const string& uid);
+ uid& operator=(const unsigned long uid);
+
+ operator string() const;
+
+ bool empty() const;
+
+ bool operator==(const uid& other) const;
+
+ private:
+
+ string m_str;
+ };
+
+ /** Return the MIME structure of the message (must fetch before).
+ *
+ * @return MIME structure of the message
+ */
+ virtual shared_ptr <const messageStructure> getStructure() const = 0;
+
+ /** Return the MIME structure of the message (must fetch before).
+ *
+ * @return MIME structure of the message
+ */
+ virtual shared_ptr <messageStructure> getStructure() = 0;
+
+ /** Return a reference to the header fields of the message (must fetch before).
+ *
+ * @return header section of the message
+ */
+ virtual shared_ptr <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 size_t getNumber() const = 0;
+
+ /** Return the unique identifier (UID) of this message in its
+ * folder (must fetch before).
+ *
+ * @return UID of the message
+ */
+ virtual const uid getUID() const = 0;
+
+ /** Return the size of the message (must fetch before).
+ *
+ * @return size of the message (in bytes)
+ */
+ virtual size_t getSize() const = 0;
+
+ /** Check whether this message has been expunged (ie: definitively
+ * deleted) and does not exist in the folder anymore.
+ *
+ * @return true if the message is expunged, false otherwise
+ */
+ virtual 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_DRAFT = (1 << 6) /**< Message is marked as a 'draft'. */
+ };
+
+ /** 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 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 progress 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::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t 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 progress 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 shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t 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(const shared_ptr <messagePart>& p) = 0;
+
+ /** Get the RFC-822 message for this abstract message.
+ * Warning: This may require getting some data (ie: structure and headers) from
+ * the server, which is done automatically. Actual message contents (ie: body)
+ * will not be fetched if possible (IMAP allows it, whereas POP3 will require
+ * to fetch the whole message).
+ *
+ * @return a RFC-822-parsed message
+ */
+ virtual shared_ptr <vmime::message> getParsedMessage() = 0;
+};
+
+
+VMIME_EXPORT std::ostream& operator<<(std::ostream& os, const message::uid& uid);
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_MESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/messageSet.cpp b/vmime-master/src/vmime/net/messageSet.cpp
new file mode 100644
index 0000000..fe2d645
--- /dev/null
+++ b/vmime-master/src/vmime/net/messageSet.cpp
@@ -0,0 +1,430 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/messageSet.hpp"
+
+#include <iterator>
+#include <algorithm>
+#include <typeinfo>
+
+
+namespace vmime {
+namespace net {
+
+// messageSetEnumerator
+
+messageSetEnumerator::~messageSetEnumerator()
+{
+}
+
+// messageRange
+
+messageRange::messageRange() {
+
+}
+
+
+messageRange::~messageRange() {
+
+}
+
+
+// numberMessageRange
+
+numberMessageRange::numberMessageRange(const size_t number)
+ : m_first(number),
+ m_last(number) {
+
+ if (number < 1) {
+ throw std::invalid_argument("number");
+ }
+}
+
+
+numberMessageRange::numberMessageRange(const size_t first, const size_t last)
+ : m_first(first),
+ m_last(last) {
+
+ if (first < 1 || first == static_cast <size_t>(-1)) {
+ throw std::invalid_argument("first");
+ } else if (last != static_cast <size_t>(-1) && last < first) {
+ throw std::invalid_argument("last");
+ }
+}
+
+
+numberMessageRange::numberMessageRange(const numberMessageRange& other)
+ : messageRange(),
+ m_first(other.m_first),
+ m_last(other.m_last) {
+
+}
+
+
+size_t numberMessageRange::getFirst() const {
+
+ return m_first;
+}
+
+
+size_t numberMessageRange::getLast() const {
+
+ return m_last;
+}
+
+
+void numberMessageRange::enumerate(messageSetEnumerator& en) const {
+
+ en.enumerateNumberMessageRange(*this);
+}
+
+
+messageRange* numberMessageRange::clone() const {
+
+ return new numberMessageRange(*this);
+}
+
+
+// UIDMessageRange
+
+UIDMessageRange::UIDMessageRange(const message::uid& uid)
+ : m_first(uid),
+ m_last(uid) {
+
+}
+
+
+UIDMessageRange::UIDMessageRange(const message::uid& first, const message::uid& last)
+ : m_first(first),
+ m_last(last) {
+
+}
+
+
+UIDMessageRange::UIDMessageRange(const UIDMessageRange& other)
+ : messageRange(),
+ m_first(other.m_first),
+ m_last(other.m_last) {
+
+}
+
+
+const message::uid UIDMessageRange::getFirst() const {
+
+ return m_first;
+}
+
+
+const message::uid UIDMessageRange::getLast() const {
+
+ return m_last;
+}
+
+
+void UIDMessageRange::enumerate(messageSetEnumerator& en) const {
+
+ en.enumerateUIDMessageRange(*this);
+}
+
+
+messageRange* UIDMessageRange::clone() const {
+
+ return new UIDMessageRange(*this);
+}
+
+
+// messageSet
+
+
+messageSet::messageSet() {
+
+}
+
+
+messageSet::messageSet(const messageSet& other)
+ : object() {
+
+ m_ranges.resize(other.m_ranges.size());
+
+ for (size_t i = 0, n = other.m_ranges.size() ; i < n ; ++i) {
+ m_ranges[i] = other.m_ranges[i]->clone();
+ }
+}
+
+
+messageSet::~messageSet() {
+
+ for (size_t i = 0, n = m_ranges.size() ; i < n ; ++i) {
+ delete m_ranges[i];
+ }
+}
+
+
+// static
+messageSet messageSet::empty() {
+
+ return messageSet();
+}
+
+
+// static
+messageSet messageSet::byNumber(const size_t number) {
+
+ messageSet set;
+ set.m_ranges.push_back(new numberMessageRange(number));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byNumber(const size_t first, const size_t last) {
+
+ messageSet set;
+ set.m_ranges.push_back(new numberMessageRange(first, last));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byNumber(const std::vector <size_t>& numbers) {
+
+ // Sort a copy of the list
+ std::vector <size_t> sortedNumbers;
+
+ sortedNumbers.resize(numbers.size());
+
+ std::copy(numbers.begin(), numbers.end(), sortedNumbers.begin());
+ std::sort(sortedNumbers.begin(), sortedNumbers.end());
+
+ // Build the set by detecting ranges of continuous numbers
+ size_t previous = static_cast <size_t>(-1), rangeStart = static_cast <size_t>(-1);
+ messageSet set;
+
+ for (std::vector <size_t>::const_iterator it = sortedNumbers.begin() ;
+ it != sortedNumbers.end() ; ++it) {
+
+ const size_t current = *it;
+
+ if (current == previous) {
+ continue; // skip duplicates
+ }
+
+ if (current == static_cast <size_t>(-1)) {
+ throw std::invalid_argument("numbers");
+ }
+
+ if (previous == static_cast <size_t>(-1)) {
+
+ previous = current;
+ rangeStart = current;
+
+ } else {
+
+ if (current == previous + 1) {
+
+ previous = current;
+
+ } else {
+
+ set.m_ranges.push_back(new numberMessageRange(rangeStart, previous));
+
+ previous = current;
+ rangeStart = current;
+ }
+ }
+ }
+
+ set.m_ranges.push_back(new numberMessageRange(rangeStart, previous));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byUID(const message::uid& uid) {
+
+ messageSet set;
+ set.m_ranges.push_back(new UIDMessageRange(uid));
+
+ return set;
+}
+
+
+messageSet messageSet::byUID(const message::uid& first, const message::uid& last) {
+
+ messageSet set;
+ set.m_ranges.push_back(new UIDMessageRange(first, last));
+
+ return set;
+}
+
+
+messageSet messageSet::byUID(const std::vector <message::uid>& uids) {
+
+ std::vector <vmime_uint32> numericUIDs;
+
+ for (size_t i = 0, n = uids.size() ; i < n ; ++i) {
+
+ const string uid = uids[i];
+ int numericUID = 0;
+
+ const char* p = uid.c_str();
+
+ for ( ; *p >= '0' && *p <= '9' ; ++p) {
+ numericUID = (numericUID * 10) + (*p - '0');
+ }
+
+ if (*p != '\0') {
+
+ messageSet set;
+
+ // Non-numeric UID, fall back to plain UID list (single-UID ranges)
+ for (size_t i = 0, n = uids.size() ; i < n ; ++i) {
+ set.m_ranges.push_back(new UIDMessageRange(uids[i]));
+ }
+
+ return set;
+ }
+
+ numericUIDs.push_back(numericUID);
+ }
+
+ // Sort a copy of the list
+ std::vector <vmime_uint32> sortedUIDs;
+
+ sortedUIDs.resize(numericUIDs.size());
+
+ std::copy(numericUIDs.begin(), numericUIDs.end(), sortedUIDs.begin());
+ std::sort(sortedUIDs.begin(), sortedUIDs.end());
+
+ // Build the set by detecting ranges of continuous numbers
+ vmime_uint32 previous = static_cast <vmime_uint32>(-1), rangeStart = static_cast <vmime_uint32>(-1);
+ messageSet set;
+
+ for (std::vector <vmime_uint32>::const_iterator it = sortedUIDs.begin() ;
+ it != sortedUIDs.end() ; ++it) {
+
+ const vmime_uint32 current = *it;
+
+ if (current == previous) {
+ continue; // skip duplicates
+ }
+
+ if (previous == static_cast <vmime_uint32>(-1)) {
+
+ previous = current;
+ rangeStart = current;
+
+ } else {
+
+ if (current == previous + 1) {
+
+ previous = current;
+
+ } else {
+
+ set.m_ranges.push_back(
+ new UIDMessageRange(
+ utility::stringUtils::toString(rangeStart),
+ utility::stringUtils::toString(previous)
+ )
+ );
+
+ previous = current;
+ rangeStart = current;
+ }
+ }
+ }
+
+ set.m_ranges.push_back(
+ new UIDMessageRange(
+ utility::stringUtils::toString(rangeStart),
+ utility::stringUtils::toString(previous)
+ )
+ );
+
+ return set;
+}
+
+
+void messageSet::addRange(const messageRange& range) {
+
+ if (!m_ranges.empty() && typeid(*m_ranges[0]) != typeid(range)) {
+ throw std::invalid_argument("range");
+ }
+
+ m_ranges.push_back(range.clone());
+}
+
+
+void messageSet::enumerate(messageSetEnumerator& en) const {
+
+ for (size_t i = 0, n = m_ranges.size() ; i < n ; ++i) {
+ m_ranges[i]->enumerate(en);
+ }
+}
+
+
+bool messageSet::isEmpty() const {
+
+ return m_ranges.empty();
+}
+
+
+bool messageSet::isNumberSet() const {
+
+ return !isEmpty() && dynamic_cast <numberMessageRange*>(m_ranges[0]) != NULL;
+}
+
+
+bool messageSet::isUIDSet() const {
+
+ return !isEmpty() && dynamic_cast <UIDMessageRange*>(m_ranges[0]) != NULL;
+}
+
+
+size_t messageSet::getRangeCount() const {
+
+ return m_ranges.size();
+}
+
+
+const messageRange& messageSet::getRangeAt(const size_t i) const {
+
+ return *m_ranges[i];
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/messageSet.hpp b/vmime-master/src/vmime/net/messageSet.hpp
new file mode 100644
index 0000000..848c4c9
--- /dev/null
+++ b/vmime-master/src/vmime/net/messageSet.hpp
@@ -0,0 +1,358 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MESSAGESET_HPP_INCLUDED
+#define VMIME_NET_MESSAGESET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/message.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+// Forward references
+class numberMessageRange;
+class UIDMessageRange;
+
+
+/** Enumerator used to retrieve the message number/UID ranges contained
+ * in a messageSet object.
+ */
+class VMIME_EXPORT messageSetEnumerator {
+
+public:
+ virtual ~messageSetEnumerator();
+ virtual void enumerateNumberMessageRange(const numberMessageRange& range) = 0;
+ virtual void enumerateUIDMessageRange(const UIDMessageRange& range) = 0;
+};
+
+
+/** A range of (continuous) messages, designated either by their
+ * sequence number, or by their UID.
+ */
+class VMIME_EXPORT messageRange : public object {
+
+public:
+
+ virtual ~messageRange();
+
+ /** Enumerates this range with the specified enumerator.
+ *
+ * @param en enumerator that will receive the method calls while
+ * enumerating this range
+ */
+ virtual void enumerate(messageSetEnumerator& en) const = 0;
+
+ /** Clones this message range.
+ */
+ virtual messageRange* clone() const = 0;
+
+protected:
+
+ messageRange();
+ messageRange(const messageRange&);
+};
+
+
+/** A range of (continuous) messages designated by their sequence number.
+ */
+class VMIME_EXPORT numberMessageRange : public messageRange {
+
+public:
+
+ /** Constructs a message range containing a single message.
+ *
+ * @param number message number (numbering starts at 1, not 0)
+ */
+ numberMessageRange(const size_t number);
+
+ /** Constructs a message range for multiple messages.
+ *
+ * @param first number of the first message in the range (numbering
+ * starts at 1, not 0)
+ * @param last number of the last message in the range, or use the
+ * special value -1 to designate the last message in the folder
+ */
+ numberMessageRange(const size_t first, const size_t last);
+
+ /** Constructs a message range by copying from another range.
+ *
+ * @param other range to copy
+ */
+ numberMessageRange(const numberMessageRange& other);
+
+ /** Returns the number of the first message in the range.
+ *
+ * @return number of the first message
+ */
+ size_t getFirst() const;
+
+ /** Returns the number of the last message in the range, or -1
+ * to designate the last message in the folder
+ *
+ * @return number of the last message
+ */
+ size_t getLast() const;
+
+ void enumerate(messageSetEnumerator& en) const;
+
+ messageRange* clone() const;
+
+private:
+
+ size_t m_first, m_last;
+};
+
+
+/** A range of (continuous) messages represented by their UID.
+ */
+class VMIME_EXPORT UIDMessageRange : public messageRange {
+
+public:
+
+ /** Constructs a message range containing a single message.
+ *
+ * @param uid message UID
+ */
+ UIDMessageRange(const message::uid& uid);
+
+ /** Constructs a message range for multiple messages.
+ *
+ * @param first UID of the first message in the range
+ * @param last UID of the last message in the range, or use the
+ * special value '*' to designate the last message in the folder
+ */
+ UIDMessageRange(const message::uid& first, const message::uid& last);
+
+ /** Constructs a message range by copying from another range.
+ *
+ * @param other range to copy
+ */
+ UIDMessageRange(const UIDMessageRange& other);
+
+ /** Returns the UID of the first message in the range.
+ *
+ * @return UID of the first message
+ */
+ const message::uid getFirst() const;
+
+ /** Returns the UID of the last message in the range, or '*'
+ * to designate the last message in the folder
+ *
+ * @return UID of the last message
+ */
+ const message::uid getLast() const;
+
+ void enumerate(messageSetEnumerator& en) const;
+
+ messageRange* clone() const;
+
+private:
+
+ message::uid m_first, m_last;
+};
+
+
+/** Represents a set of messages, designated either by their sequence
+ * number, or by their UID (but not both).
+ *
+ * Following is example code to designate messages by their number:
+ * \code{.cpp}
+ * // Designate a single message with sequence number 42
+ * vmime::net::messageSet::byNumber(42)
+ *
+ * // Designate messages from sequence number 5 to sequence number 8 (including)
+ * vmime::net::messageSet::byNumber(5, 8)
+ *
+ * // Designate all messages in the folder, starting from number 42
+ * vmime::net::messageSet::byNumber(42, -1)
+ * \endcode
+ * Or, to designate messages by their UID, use:
+ * \code{.cpp}
+ * // Designate a single message with UID 1042
+ * vmime::net::messageSet::byUID(1042)
+ *
+ * // Designate messages from UID 1000 to UID 1042 (including)
+ * vmime::net::messageSet::byUID(1000, 1042)
+ *
+ * // Designate all messages in the folder, starting from UID 1000
+ * vmime::net::messageSet::byUID(1000, "*")
+ * \endcode
+ */
+class VMIME_EXPORT messageSet : public object {
+
+public:
+
+ ~messageSet();
+
+ messageSet(const messageSet& other);
+
+ /** Constructs an empty set.
+ *
+ * @return new empty message set
+ */
+ static messageSet empty();
+
+ /** Constructs a new message set and initializes it with a single
+ * message represented by its sequence number.
+ *
+ * @param number message number (numbering starts at 1, not 0)
+ * @return new message set
+ */
+ static messageSet byNumber(const size_t number);
+
+ /** Constructs a new message set and initializes it with a range
+ * of messages represented by their sequence number.
+ *
+ * @param first number of the first message in the range (numbering
+ * starts at 1, not 0)
+ * @param last number of the last message in the range, or use the
+ * special value -1 to designate the last message in the folder
+ * @return new message set
+ */
+ static messageSet byNumber(const size_t first, const size_t last);
+
+ /** Constructs a new message set and initializes it with a possibly
+ * unsorted list of messages represented by their sequence number.
+ * Please note that numbering starts at 1, not 0.
+ *
+ * The function tries to group consecutive message numbers into
+ * ranges to reduce the size of the resulting set.
+ *
+ * For example, given the list "1,2,3,4,5,7,8,13,15,16,17" it will
+ * result in the following ranges: "1:5,7:8,13,15:17".
+ *
+ * @param numbers a vector containing numbers of the messages
+ * @return new message set
+ */
+ static messageSet byNumber(const std::vector <size_t>& numbers);
+
+ /** Constructs a new message set and initializes it with a single
+ * message represented by its UID.
+ *
+ * @param uid message UID
+ * @return new message set
+ */
+ static messageSet byUID(const message::uid& uid);
+
+ /** Constructs a new message set and initializes it with a range
+ * of messages represented by their sequence number.
+ *
+ * @param first UID of the first message in the range
+ * @param last UID of the last message in the range, or use the
+ * special value '*' to designate the last message in the folder
+ * @return new message set
+ */
+ static messageSet byUID(const message::uid& first, const message::uid& last);
+
+ /** Constructs a new message set and initializes it with a possibly
+ * unsorted list of messages represented by their UID.
+ *
+ * For UIDs that actually are numbers (this is the case for IMAP), the
+ * function tries to group consecutive UIDs into ranges to reduce the
+ * size of the resulting set.
+ *
+ * For example, given the list "1,2,3,4,5,7,8,13,15,16,17" it will
+ * result in the following ranges: "1:5,7:8,13,15:17".
+ *
+ * @param uids a vector containing UIDs of the messages
+ * @return new message set
+ */
+ static messageSet byUID(const std::vector <message::uid>& uids);
+
+ /** Adds the specified range to this set. The type of message range
+ * (either number or UID) must match the type of the ranges already
+ * contained in this set (ie. it's not possible to have a message
+ * set which contains both number ranges and UID ranges).
+ *
+ * @param range range to add
+ * @throw std::invalid_argument exception if the range type does
+ * not match the type of the ranges in this set
+ */
+ void addRange(const messageRange& range);
+
+ /** Enumerates this set with the specified enumerator.
+ *
+ * @param en enumerator that will receive the method calls while
+ * enumerating the ranges in this set
+ */
+ void enumerate(messageSetEnumerator& en) const;
+
+ /** Returns whether this set is empty (contains no range).
+ *
+ * @return true if this set is empty, or false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Returns whether this set references messages by their sequence
+ * number.
+ *
+ * @return true if this set references messages by their sequence
+ * number, or false otherwise
+ */
+ bool isNumberSet() const;
+
+ /** Returns whether this set references messages by their UID.
+ *
+ * @return true if this set references messages by their UID,
+ * or false otherwise
+ */
+ bool isUIDSet() const;
+
+ /** Returns the number of ranges contained in this set.
+ *
+ * @return range count
+ */
+ size_t getRangeCount() const;
+
+ /** Returns the message range at the specified index.
+ *
+ * @param i range index (from 0 to getRangeCount())
+ * @return a reference to the message range at the specified index
+ */
+ const messageRange& getRangeAt(const size_t i) const;
+
+private:
+
+ messageSet();
+
+ std::vector <messageRange*> m_ranges;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_MESSAGESET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Command.cpp b/vmime-master/src/vmime/net/pop3/POP3Command.cpp
new file mode 100644
index 0000000..0e79888
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Command.cpp
@@ -0,0 +1,267 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Connection.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+#include "vmime/net/socket.hpp"
+
+#include "vmime/mailbox.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Command::POP3Command(const string& text, const string& traceText)
+ : m_text(text),
+ m_traceText(traceText) {
+
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::CAPA() {
+
+ return createCommand("CAPA");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::NOOP() {
+
+ return createCommand("NOOP");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::AUTH(const string& mechName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::AUTH(const string& mechName, const string& initialResponse) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName << " " << initialResponse;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::STLS() {
+
+ return createCommand("STLS");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::APOP(const string& username, const string& digest) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "APOP " << username << " " << digest;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::USER(const string& username) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "USER " << username;
+
+ std::ostringstream trace;
+ trace.imbue(std::locale::classic());
+ trace << "USER {username}";
+
+ return createCommand(cmd.str(), trace.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::PASS(const string& password) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "PASS " << password;
+
+ std::ostringstream trace;
+ trace.imbue(std::locale::classic());
+ trace << "PASS {password}";
+
+ return createCommand(cmd.str(), trace.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::STAT() {
+
+ return createCommand("STAT");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::LIST() {
+
+ return createCommand("LIST");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::LIST(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LIST " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::UIDL() {
+
+ return createCommand("UIDL");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::UIDL(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "UIDL " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::DELE(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "DELE " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::RETR(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "RETR " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::TOP(const unsigned long msg, const unsigned long lines) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "TOP " << msg << " " << lines;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::RSET() {
+
+ return createCommand("RSET");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::QUIT() {
+
+ return createCommand("QUIT");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::createCommand(
+ const string& text,
+ const string& traceText
+) {
+
+ if (traceText.empty()) {
+ return shared_ptr <POP3Command>(new POP3Command(text, text));
+ } else {
+ return shared_ptr <POP3Command>(new POP3Command(text, traceText));
+ }
+}
+
+
+const string POP3Command::getText() const {
+
+ return m_text;
+}
+
+
+const string POP3Command::getTraceText() const {
+
+ return m_traceText;
+}
+
+
+void POP3Command::send(const shared_ptr <POP3Connection>& conn) {
+
+ conn->getSocket()->send(m_text + "\r\n");
+
+ if (conn->getTracer()) {
+ conn->getTracer()->traceSend(m_traceText);
+ }
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3Command.hpp b/vmime-master/src/vmime/net/pop3/POP3Command.hpp
new file mode 100644
index 0000000..06a61b9
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Command.hpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3COMMAND_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3COMMAND_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+
+
+class mailbox;
+
+
+namespace net {
+namespace pop3 {
+
+
+class POP3Connection;
+
+
+/** A POP3 command that will be sent to the server.
+ */
+class VMIME_EXPORT POP3Command : public object {
+
+public:
+
+ static shared_ptr <POP3Command> CAPA();
+ static shared_ptr <POP3Command> NOOP();
+ static shared_ptr <POP3Command> AUTH(const string& mechName);
+ static shared_ptr <POP3Command> AUTH(const string& mechName, const string& initialResponse);
+ static shared_ptr <POP3Command> STLS();
+ static shared_ptr <POP3Command> APOP(const string& username, const string& digest);
+ static shared_ptr <POP3Command> USER(const string& username);
+ static shared_ptr <POP3Command> PASS(const string& password);
+ static shared_ptr <POP3Command> STAT();
+ static shared_ptr <POP3Command> LIST();
+ static shared_ptr <POP3Command> LIST(const unsigned long msg);
+ static shared_ptr <POP3Command> UIDL();
+ static shared_ptr <POP3Command> UIDL(const unsigned long msg);
+ static shared_ptr <POP3Command> DELE(const unsigned long msg);
+ static shared_ptr <POP3Command> RETR(const unsigned long msg);
+ static shared_ptr <POP3Command> TOP(const unsigned long msg, const unsigned long lines);
+ static shared_ptr <POP3Command> RSET();
+ static shared_ptr <POP3Command> QUIT();
+
+ /** Creates a new POP3 command with the specified text.
+ *
+ * @param text command text
+ * @param traceText trace text (if empty, command text is used)
+ * @return a new POP3Command object
+ */
+ static shared_ptr <POP3Command> createCommand(const string& text, const string& traceText = "");
+
+ /** Sends this command over the specified connection.
+ *
+ * @param conn connection onto which the command will be sent
+ */
+ virtual void send(const shared_ptr <POP3Connection>& conn);
+
+ /** Returns the full text of the command, including command name
+ * and parameters (if any).
+ *
+ * @return command text (eg. "LIST 42")
+ */
+ virtual const string getText() const;
+
+ /** Returns the full text of the command, suitable for outputing
+ * to the tracer.
+ *
+ * @return trace text (eg. "USER myusername")
+ */
+ virtual const string getTraceText() const;
+
+protected:
+
+ POP3Command(const string& text, const string& traceText);
+ POP3Command(const POP3Command&);
+
+private:
+
+ string m_text;
+ string m_traceText;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3COMMAND_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Connection.cpp b/vmime-master/src/vmime/net/pop3/POP3Connection.cpp
new file mode 100644
index 0000000..749f7ef
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Connection.cpp
@@ -0,0 +1,737 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Connection.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/SASLContext.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/tls/TLSSession.hpp"
+ #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (m_store.lock()->getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const POP3ServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (m_store.lock()->getInfos().hasProperty(getSession(), \
+ dynamic_cast <const POP3ServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+
+POP3Connection::POP3Connection(
+ const shared_ptr <POP3Store>& store,
+ const shared_ptr <security::authenticator>& auth
+)
+ : m_store(store),
+ m_auth(auth),
+ m_socket(null),
+ m_timeoutHandler(null),
+ m_authenticated(false),
+ m_secured(false),
+ m_capabilitiesFetched(false) {
+
+ static int connectionId = 0;
+
+ if (store->getTracerFactory()) {
+ m_tracer = store->getTracerFactory()->create(store, ++connectionId);
+ }
+}
+
+
+POP3Connection::~POP3Connection() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ } else if (m_socket) {
+ internalDisconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void POP3Connection::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);
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ // Create the time-out handler
+ if (store->getTimeoutHandlerFactory()) {
+ m_timeoutHandler = store->getTimeoutHandlerFactory()->create();
+ }
+
+ // Create and connect the socket
+ m_socket = store->getSocketFactory()->create(m_timeoutHandler);
+ m_socket->setTracer(m_tracer);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (store->isPOP3S()) { // dedicated port/POP3S
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create
+ (store->getCertificateVerifier(),
+ store->getSession()->getTLSProperties());
+
+ shared_ptr <tls::TLSSocket> tlsSocket =
+ tlsSession->getSocket(m_socket);
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
+ } else
+#endif // VMIME_HAVE_TLS_SUPPORT
+ {
+ m_cntInfos = make_shared <defaultConnectionInfos>(address, port);
+ }
+
+ m_socket->connect(address, port);
+
+ // Connection
+ //
+ // eg: C: <connection to server>
+ // --- S: +OK MailSite POP3 Server 5.3.4.0 Ready <36938848.1056800841.634@somewhere.com>
+
+ shared_ptr <POP3Response> response = POP3Response::readResponse(
+ dynamicCast <POP3Connection>(shared_from_this())
+ );
+
+ if (!response->isSuccess()) {
+
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(response->getFirstLine());
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+ // Setup secured connection, if requested
+ const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);
+ const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);
+
+ if (!store->isPOP3S() && tls) { // only if not POP3S
+
+ try {
+
+ startTLS();
+
+ // Non-fatal error
+ } catch (exceptions::command_error&) {
+
+ if (tlsRequired) {
+ throw;
+ } else {
+ // TLS is not required, so don't bother
+ }
+
+ // Fatal error
+ } catch (...) {
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // Start authentication process
+ authenticate(messageId(response->getText()));
+}
+
+
+void POP3Connection::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ internalDisconnect();
+}
+
+
+void POP3Connection::internalDisconnect() {
+
+ if (m_socket) {
+
+ if (m_socket->isConnected()) {
+
+ try {
+
+ POP3Command::QUIT()->send(dynamicCast <POP3Connection>(shared_from_this()));
+ POP3Response::readResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ } catch (exception&) {
+
+ // Not important
+ }
+
+ m_socket->disconnect();
+ }
+
+ m_socket = null;
+ }
+
+ m_timeoutHandler = null;
+
+ m_authenticated = false;
+ m_secured = false;
+
+ m_cntInfos = null;
+}
+
+
+void POP3Connection::authenticate(const messageId& randomMID) {
+
+ getAuthenticator()->setService(m_store.lock());
+
+#if VMIME_HAVE_SASL_SUPPORT
+ // First, try SASL authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) {
+
+ try {
+
+ authenticateSASL();
+
+ m_authenticated = true;
+ return;
+
+ } catch (exceptions::authentication_error&) {
+
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK)) {
+
+ // Can't fallback on APOP/normal authentication
+ internalDisconnect();
+ throw;
+
+ } else {
+
+ // Ignore, will try APOP/normal authentication
+ }
+
+ } catch (exception&) {
+
+ internalDisconnect();
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Secured authentication with APOP (if requested and if available)
+ //
+ // eg: C: APOP vincent <digest>
+ // --- S: +OK vincent is a valid mailbox
+
+ const string username = getAuthenticator()->getUsername();
+ const string password = getAuthenticator()->getPassword();
+
+ shared_ptr <POP3Connection> conn = dynamicCast <POP3Connection>(shared_from_this());
+ shared_ptr <POP3Response> response;
+
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP)) {
+
+ if (randomMID.getLeft().length() != 0 &&
+ randomMID.getRight().length() != 0) {
+
+ // <digest> is the result of MD5 applied to "<message-id>password"
+ shared_ptr <security::digest::messageDigest> md5 =
+ security::digest::messageDigestFactory::getInstance()->create("md5");
+
+ md5->update(randomMID.generate() + password);
+ md5->finalize();
+
+ POP3Command::APOP(username, md5->getHexDigest())->send(conn);
+ response = POP3Response::readResponse(conn);
+
+ if (response->isSuccess()) {
+
+ m_authenticated = true;
+ return;
+
+ } else {
+
+ // Some servers close the connection after an unsuccessful APOP
+ // command, so the fallback may not always work...
+ //
+ // S: +OK Qpopper (version 4.0.5) at xxx starting. <30396.1126730747@xxx>
+ // C: APOP plop c5e0a87d088ec71d60e32692d4c5bdf4
+ // S: -ERR [AUTH] Password supplied for "plop" is incorrect.
+ // S: +OK Pop server at xxx signing off.
+ // [Connection closed by foreign host.]
+
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK)) {
+
+ // Can't fallback on basic authentication
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+
+ // Ensure connection is valid (cf. note above)
+ try {
+
+ POP3Command::NOOP()->send(conn);
+ POP3Response::readResponse(conn);
+
+ } catch (exceptions::socket_exception&) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+ }
+
+ } else {
+
+ // APOP not supported
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK)) {
+
+ // Can't fallback on basic authentication
+ internalDisconnect();
+ throw exceptions::authentication_error("APOP not supported");
+ }
+ }
+ }
+
+ // Basic authentication
+ //
+ // eg: C: USER vincent
+ // --- S: +OK vincent is a valid mailbox
+ //
+ // C: PASS couic
+ // S: +OK vincent's maildrop has 2 messages (320 octets)
+ POP3Command::USER(username)->send(conn);
+ response = POP3Response::readResponse(conn);
+
+ if (!response->isSuccess()) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+
+ POP3Command::PASS(password)->send(conn);
+ response = POP3Response::readResponse(conn);
+
+ if (!response->isSuccess()) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+
+ m_authenticated = true;
+}
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+void POP3Connection::authenticateSASL() {
+
+ if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) {
+ throw exceptions::authentication_error("No SASL authenticator available.");
+ }
+
+ std::vector <string> capa = getCapabilities();
+ std::vector <string> saslMechs;
+
+ for (unsigned int i = 0 ; i < capa.size() ; ++i) {
+
+ const string& x = capa[i];
+
+ // C: CAPA
+ // S: +OK List of capabilities follows
+ // S: LOGIN-DELAY 0
+ // S: PIPELINING
+ // S: UIDL
+ // S: ...
+ // S: SASL DIGEST-MD5 CRAM-MD5 <-----
+ // S: EXPIRE NEVER
+ // S: ...
+
+ if (x.length() > 5 &&
+ (x[0] == 'S' || x[0] == 's') &&
+ (x[1] == 'A' || x[1] == 'a') &&
+ (x[2] == 'S' || x[2] == 's') &&
+ (x[3] == 'L' || x[3] == 'l') &&
+ (x[4] == ' ' || x[4] == '\t')) {
+
+ const string list(x.begin() + 5, x.end());
+
+ std::istringstream iss(list);
+ iss.imbue(std::locale::classic());
+
+ string mech;
+
+ while (iss >> mech) {
+ saslMechs.push_back(mech);
+ }
+ }
+ }
+
+ if (saslMechs.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList;
+
+ shared_ptr <security::sasl::SASLContext> saslContext =
+ security::sasl::SASLContext::create();
+
+ for (unsigned int i = 0 ; i < saslMechs.size() ; ++i) {
+
+ try {
+ mechList.push_back(saslContext->createMechanism(saslMechs[i]));
+ } catch (exceptions::no_such_mechanism&) {
+ // Ignore mechanism
+ }
+ }
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try to suggest a mechanism among all those supported
+ shared_ptr <security::sasl::SASLMechanism> suggestedMech =
+ saslContext->suggestMechanism(mechList);
+
+ if (!suggestedMech) {
+ throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
+ }
+
+ // Allow application to choose which mechanisms to use
+ mechList = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())->
+ getAcceptableMechanisms(mechList, suggestedMech);
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try each mechanism in the list in turn
+ for (unsigned int i = 0 ; i < mechList.size() ; ++i) {
+
+ shared_ptr <security::sasl::SASLMechanism> mech = mechList[i];
+
+ shared_ptr <security::sasl::SASLSession> saslSession =
+ saslContext->createSession("pop3", getAuthenticator(), mech);
+
+ saslSession->init();
+
+ shared_ptr <POP3Command> authCmd;
+
+ if (saslSession->getMechanism()->hasInitialResponse()) {
+
+ byte_t* initialResp = 0;
+ size_t initialRespLen = 0;
+
+ saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
+
+ string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
+ delete [] initialResp;
+
+ if (encodedInitialResp.empty()) {
+ authCmd = POP3Command::AUTH(mech->getName(), "=");
+ } else {
+ authCmd = POP3Command::AUTH(mech->getName(), encodedInitialResp);
+ }
+
+ } else {
+
+ authCmd = POP3Command::AUTH(mech->getName());
+ }
+
+ authCmd->send(dynamicCast <POP3Connection>(shared_from_this()));
+
+ for (bool cont = true ; cont ; ) {
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ switch (response->getCode()) {
+
+ case POP3Response::CODE_OK: {
+
+ m_socket = saslSession->getSecuredSocket(m_socket);
+ return;
+ }
+
+ case POP3Response::CODE_READY: {
+
+ byte_t* challenge = 0;
+ size_t challengeLen = 0;
+
+ byte_t* resp = 0;
+ size_t respLen = 0;
+
+ try {
+
+ // Extract challenge
+ saslContext->decodeB64(response->getText(), &challenge, &challengeLen);
+
+ // Prepare response
+ saslSession->evaluateChallenge(challenge, challengeLen, &resp, &respLen);
+
+ // Send response
+ const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n";
+ m_socket->sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length());
+
+ if (m_tracer) {
+ m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange");
+ }
+
+ } catch (exceptions::sasl_exception& e) {
+
+ if (challenge) {
+ delete [] challenge;
+ challenge = NULL;
+ }
+
+ if (resp) {
+ delete [] resp;
+ resp = NULL;
+ }
+
+ // Cancel SASL exchange
+ m_socket->send("*\r\n");
+
+ if (m_tracer) {
+ m_tracer->traceSend("*");
+ }
+
+ } catch (...) {
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ throw;
+ }
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ break;
+ }
+
+ default:
+
+ cont = false;
+ break;
+ }
+ }
+ }
+
+ throw exceptions::authentication_error("Could not authenticate using SASL: all mechanisms failed.");
+}
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void POP3Connection::startTLS() {
+
+ try {
+
+ POP3Command::STLS()->send(dynamicCast <POP3Connection>(shared_from_this()));
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("STLS", response->getFirstLine());
+ }
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ m_store.lock()->getCertificateVerifier(),
+ m_store.lock()->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ tlsSocket->handshake();
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(
+ m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket
+ );
+
+ // " Once TLS has been started, the client MUST discard cached
+ // information about server capabilities and SHOULD re-issue
+ // the CAPA command. This is necessary to protect against
+ // man-in-the-middle attacks which alter the capabilities list
+ // prior to STLS. " (RFC-2595)
+ invalidateCapabilities();
+
+ } catch (exceptions::command_error&) {
+
+ // Non-fatal error
+ throw;
+
+ } catch (exception&) {
+
+ // Fatal error
+ internalDisconnect();
+ throw;
+ }
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+const std::vector <string> POP3Connection::getCapabilities() {
+
+ if (!m_capabilitiesFetched) {
+ fetchCapabilities();
+ }
+
+ return m_capabilities;
+}
+
+
+void POP3Connection::invalidateCapabilities() {
+
+ m_capabilities.clear();
+ m_capabilitiesFetched = false;
+}
+
+
+void POP3Connection::fetchCapabilities() {
+
+ POP3Command::CAPA()->send(dynamicCast <POP3Connection>(shared_from_this()));
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readMultilineResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ std::vector <string> res;
+
+ if (response->isSuccess()) {
+
+ for (size_t i = 0, n = response->getLineCount() ; i < n ; ++i) {
+ res.push_back(response->getLineAt(i));
+ }
+ }
+
+ m_capabilities = res;
+ m_capabilitiesFetched = true;
+}
+
+
+bool POP3Connection::isConnected() const {
+
+ return m_socket && m_socket->isConnected() && m_authenticated;
+}
+
+
+bool POP3Connection::isSecuredConnection() const {
+
+ return m_secured;
+}
+
+
+shared_ptr <connectionInfos> POP3Connection::getConnectionInfos() const {
+
+ return m_cntInfos;
+}
+
+
+shared_ptr <POP3Store> POP3Connection::getStore() {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <session> POP3Connection::getSession() {
+
+ return m_store.lock()->getSession();
+}
+
+
+shared_ptr <socket> POP3Connection::getSocket() {
+
+ return m_socket;
+}
+
+
+shared_ptr <tracer> POP3Connection::getTracer() {
+
+ return m_tracer;
+}
+
+
+shared_ptr <timeoutHandler> POP3Connection::getTimeoutHandler() {
+
+ return m_timeoutHandler;
+}
+
+
+shared_ptr <security::authenticator> POP3Connection::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3Connection.hpp b/vmime-master/src/vmime/net/pop3/POP3Connection.hpp
new file mode 100644
index 0000000..26b3f3c
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Connection.hpp
@@ -0,0 +1,132 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3CONNECTION_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3CONNECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/messageId.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/session.hpp"
+#include "vmime/net/connectionInfos.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+
+
+namespace pop3 {
+
+
+class POP3Store;
+
+
+/** Manage connection to a POP3 server.
+ */
+class VMIME_EXPORT POP3Connection : public object, public enable_shared_from_this <POP3Connection> {
+
+public:
+
+ POP3Connection(
+ const shared_ptr <POP3Store>& store,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ virtual ~POP3Connection();
+
+
+ virtual void connect();
+ virtual bool isConnected() const;
+ virtual void disconnect();
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ virtual shared_ptr <POP3Store> getStore();
+ virtual shared_ptr <socket> getSocket();
+ virtual shared_ptr <timeoutHandler> getTimeoutHandler();
+ virtual shared_ptr <security::authenticator> getAuthenticator();
+ virtual shared_ptr <session> getSession();
+ virtual shared_ptr <tracer> getTracer();
+
+private:
+
+ void authenticate(const messageId& randomMID);
+#if VMIME_HAVE_SASL_SUPPORT
+ void authenticateSASL();
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ void startTLS();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ void fetchCapabilities();
+ void invalidateCapabilities();
+ const std::vector <string> getCapabilities();
+
+ void internalDisconnect();
+
+
+ weak_ptr <POP3Store> m_store;
+
+ shared_ptr <security::authenticator> m_auth;
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ bool m_authenticated;
+ bool m_secured;
+
+ shared_ptr <connectionInfos> m_cntInfos;
+
+ std::vector <string> m_capabilities;
+ bool m_capabilitiesFetched;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3CONNECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Folder.cpp b/vmime-master/src/vmime/net/pop3/POP3Folder.cpp
new file mode 100644
index 0000000..b69a483
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Folder.cpp
@@ -0,0 +1,822 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Folder.hpp"
+
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3Message.hpp"
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+#include "vmime/net/pop3/POP3FolderStatus.hpp"
+
+#include "vmime/net/pop3/POP3Utils.hpp"
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Folder::POP3Folder(
+ const folder::path& path,
+ const shared_ptr <POP3Store>& store
+)
+ : m_store(store),
+ m_path(path),
+ m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()),
+ m_mode(-1),
+ m_open(false) {
+
+ store->registerFolder(this);
+}
+
+
+POP3Folder::~POP3Folder() {
+
+ try {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (store) {
+
+ if (m_open) {
+ close(false);
+ }
+
+ store->unregisterFolder(this);
+
+ } else if (m_open) {
+
+ onClose();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+int POP3Folder::getMode() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_mode;
+}
+
+
+const folderAttributes POP3Folder::getAttributes() {
+
+ folderAttributes attribs;
+
+ if (m_path.isEmpty()) {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
+ } else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX") {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_MESSAGES);
+ attribs.setSpecialUse(folderAttributes::SPECIALUSE_INBOX);
+ } else {
+ throw exceptions::folder_not_found();
+ }
+
+ attribs.setFlags(0);
+
+ return attribs;
+}
+
+
+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) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!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") {
+
+ POP3Command::STAT()->send(store->getConnection());
+
+ shared_ptr <POP3Response> response = POP3Response::readResponse(store->getConnection());
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("STAT", response->getFirstLine());
+ }
+
+ std::istringstream iss(response->getText());
+ iss.imbue(std::locale::classic());
+ iss >> m_messageCount;
+
+ if (iss.fail()) {
+ throw exceptions::invalid_response("STAT", response->getFirstLine());
+ }
+
+ m_open = true;
+ m_mode = mode;
+
+ } else {
+
+ throw exceptions::folder_not_found();
+ }
+}
+
+
+void POP3Folder::close(const bool expunge) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (!expunge) {
+ POP3Command::RSET()->send(store->getConnection());
+ POP3Response::readResponse(store->getConnection());
+ }
+
+ 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 folderAttributes& /* attribs */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::destroy() {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+bool POP3Folder::exists() {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return m_path.isEmpty() || (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX");
+}
+
+
+bool POP3Folder::isOpen() const {
+
+ return m_open;
+}
+
+
+shared_ptr <message> POP3Folder::getMessage(const size_t num) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!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 make_shared <POP3Message>(dynamicCast <POP3Folder>(shared_from_this()), num);
+}
+
+
+std::vector <shared_ptr <message> > POP3Folder::getMessages(const messageSet& msgs) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isNumberSet()) {
+
+ const std::vector <size_t> numbers = POP3Utils::messageSetToNumberList(msgs, m_messageCount);
+
+ std::vector <shared_ptr <message> > messages;
+ shared_ptr <POP3Folder> thisFolder(dynamicCast <POP3Folder>(shared_from_this()));
+
+ for (std::vector <size_t>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) {
+
+ if (*it < 1|| *it > m_messageCount) {
+ throw exceptions::message_not_found();
+ }
+
+ messages.push_back(make_shared <POP3Message>(thisFolder, *it));
+ }
+
+ return messages;
+
+ } else {
+
+ throw exceptions::operation_not_supported();
+ }
+}
+
+
+size_t POP3Folder::getMessageCount() {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_messageCount;
+}
+
+
+shared_ptr <folder> POP3Folder::getFolder(const folder::path::component& name) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return shared_ptr <POP3Folder>(new POP3Folder(m_path / name, store));
+}
+
+
+std::vector <shared_ptr <folder> > POP3Folder::getFolders(const bool /* recursive */) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (m_path.isEmpty()) {
+
+ std::vector <shared_ptr <folder> > v;
+ v.push_back(shared_ptr <POP3Folder>(new POP3Folder(folder::path::component("INBOX"), store)));
+ return v;
+
+ } else {
+
+ std::vector <shared_ptr <folder> > v;
+ return v;
+ }
+}
+
+
+void POP3Folder::fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msg.empty()) {
+ return;
+ }
+
+ const size_t total = msg.size();
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ dynamicCast <POP3Message>(*it)->fetch(
+ dynamicCast <POP3Folder>(shared_from_this()),
+ options
+ );
+
+ if (progress) {
+ progress->progress(++current, total);
+ }
+ }
+
+ if (options.has(fetchAttributes::SIZE)) {
+
+ // Send the "LIST" command
+ POP3Command::LIST()->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readMultilineResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ // C: LIST
+ // S: +OK
+ // S: 1 47548
+ // S: 2 12653
+ // S: .
+ std::map <size_t, string> result;
+ POP3Utils::parseMultiListOrUidlResponse(response, result);
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ shared_ptr <POP3Message> m = dynamicCast <POP3Message>(*it);
+
+ std::map <size_t, string>::const_iterator x = result.find(m->m_num);
+
+ if (x != result.end()) {
+
+ size_t size = 0;
+
+ std::istringstream iss((*x).second);
+ iss.imbue(std::locale::classic());
+ iss >> size;
+
+ m->m_size = size;
+ }
+ }
+ }
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+
+ // Send the "UIDL" command
+ POP3Command::UIDL()->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readMultilineResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ // C: UIDL
+ // S: +OK
+ // S: 1 whqtswO00WBw418f9t5JxYwZ
+ // S: 2 QhdPYR:00WBw1Ph7x7
+ // S: .
+ std::map <size_t, string> result;
+ POP3Utils::parseMultiListOrUidlResponse(response, result);
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ shared_ptr <POP3Message> m = dynamicCast <POP3Message>(*it);
+
+ std::map <size_t, 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(const shared_ptr <message>& msg, const fetchAttributes& options) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ dynamicCast <POP3Message>(msg)->fetch(
+ dynamicCast <POP3Folder>(shared_from_this()),
+ options
+ );
+
+ if (options.has(fetchAttributes::SIZE)) {
+
+ // Send the "LIST" command
+ POP3Command::LIST(msg->getNumber())->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ string responseText = response->getText();
+
+ // C: LIST 2
+ // S: +OK 2 4242
+ string::iterator it = responseText.begin();
+
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+
+ if (it != responseText.end()) {
+
+ size_t size = 0;
+
+ std::istringstream iss(string(it, responseText.end()));
+ iss.imbue(std::locale::classic());
+ iss >> size;
+
+ dynamicCast <POP3Message>(msg)->m_size = size;
+ }
+ }
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+
+ // Send the "UIDL" command
+ POP3Command::UIDL(msg->getNumber())->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ string responseText = response->getText();
+
+ // C: UIDL 2
+ // S: +OK 2 QhdPYR:00WBw1Ph7x7
+ string::iterator it = responseText.begin();
+
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+
+ if (it != responseText.end()) {
+ dynamicCast <POP3Message>(msg)->m_uid = string(it, responseText.end());
+ }
+ }
+ }
+}
+
+
+std::vector <shared_ptr <message> > POP3Folder::getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+) {
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ std::vector <shared_ptr <message> > messages = getMessages(msgs);
+ fetchMessages(messages, attribs);
+
+ return messages;
+}
+
+
+int POP3Folder::getFetchCapabilities() const {
+
+ return fetchAttributes::ENVELOPE |
+ fetchAttributes::CONTENT_INFO |
+ fetchAttributes::SIZE |
+ fetchAttributes::FULL_HEADER |
+ fetchAttributes::UID |
+ fetchAttributes::IMPORTANCE;
+}
+
+
+shared_ptr <folder> POP3Folder::getParent() {
+
+ if (m_path.isEmpty()) {
+ return null;
+ } else {
+ return shared_ptr <POP3Folder>(new POP3Folder(m_path.getParent(), m_store.lock()));
+ }
+}
+
+
+shared_ptr <const store> POP3Folder::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <store> POP3Folder::getStore() {
+
+ return m_store.lock();
+}
+
+
+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.reset();
+}
+
+
+void POP3Folder::deleteMessages(const messageSet& msgs) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ const std::vector <size_t> nums = POP3Utils::messageSetToNumberList(msgs, m_messageCount);
+
+ if (nums.empty()) {
+ throw exceptions::invalid_argument();
+ }
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ for (std::vector <size_t>::const_iterator
+ it = nums.begin() ; it != nums.end() ; ++it) {
+
+ POP3Command::DELE(*it)->send(store->getConnection());
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("DELE", response->getFirstLine());
+ }
+ }
+
+ // Sort message list
+ std::vector <size_t> 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*, size_t>::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
+ shared_ptr <events::messageChangedEvent> event =
+ make_shared <events::messageChangedEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageChangedEvent::TYPE_FLAGS,
+ list
+ );
+
+ notifyMessageChanged(event);
+}
+
+
+void POP3Folder::setMessageFlags(
+ const messageSet& /* msgs */,
+ const int /* flags */,
+ const int /* mode */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::rename(const folder::path& /* newPath */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+messageSet POP3Folder::addMessage(
+ const shared_ptr <vmime::message>& /* msg */,
+ const int /* flags */,
+ vmime::datetime* /* date */,
+ utility::progressListener* /* progress */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+messageSet POP3Folder::addMessage(
+ utility::inputStream& /* is */,
+ const size_t /* size */,
+ const int /* flags */,
+ vmime::datetime* /* date */,
+ utility::progressListener* /* progress */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+messageSet POP3Folder::copyMessages(
+ const folder::path& /* dest */,
+ const messageSet& /* msgs */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::status(size_t& count, size_t& unseen) {
+
+ count = 0;
+ unseen = 0;
+
+ shared_ptr <folderStatus> status = getStatus();
+
+ count = status->getMessageCount();
+ unseen = status->getUnseenCount();
+
+ m_messageCount = count;
+}
+
+
+shared_ptr <folderStatus> POP3Folder::getStatus() {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ POP3Command::STAT()->send(store->getConnection());
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("STAT", response->getFirstLine());
+ }
+
+
+ size_t count = 0;
+
+ std::istringstream iss(response->getText());
+ iss.imbue(std::locale::classic());
+ iss >> count;
+
+ shared_ptr <POP3FolderStatus> status = make_shared <POP3FolderStatus>();
+
+ status->setMessageCount(count);
+ status->setUnseenCount(count);
+
+ // Update local message count
+ if (m_messageCount != count) {
+
+ const size_t oldCount = m_messageCount;
+
+ m_messageCount = count;
+
+ if (count > oldCount) {
+
+ std::vector <size_t> nums;
+ nums.resize(count - oldCount);
+
+ for (size_t i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j) {
+ nums[j] = i;
+ }
+
+ // Notify message count changed
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <POP3Folder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = count;
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+
+void POP3Folder::expunge() {
+
+ // Not supported by POP3 protocol (deleted messages are automatically
+ // expunged at the end of the session...).
+}
+
+
+std::vector <size_t> POP3Folder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Folder.hpp b/vmime-master/src/vmime/net/pop3/POP3Folder.hpp
new file mode 100644
index 0000000..73e29f9
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Folder.hpp
@@ -0,0 +1,179 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include <vector>
+#include <map>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/folder.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Store;
+class POP3Message;
+
+
+/** POP3 folder implementation.
+ */
+class VMIME_EXPORT POP3Folder : public folder {
+
+private:
+
+ friend class POP3Store;
+ friend class POP3Message;
+
+ POP3Folder(const POP3Folder&);
+ POP3Folder(const folder::path& path, const shared_ptr <POP3Store>& store);
+
+public:
+
+ ~POP3Folder();
+
+ int getMode() const;
+
+ const folderAttributes getAttributes();
+
+ 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 folderAttributes& attribs);
+
+ bool exists();
+
+ void destroy();
+
+ bool isOpen() const;
+
+ shared_ptr <message> getMessage(const size_t num);
+ std::vector <shared_ptr <message> > getMessages(const messageSet& msgs);
+
+ size_t getMessageCount();
+
+ shared_ptr <folder> getFolder(const folder::path::component& name);
+ std::vector <shared_ptr <folder> > getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessages(const messageSet& msgs);
+
+ void setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode = message::FLAG_MODE_SET
+ );
+
+ messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet copyMessages(const folder::path& dest, const messageSet& msgs);
+
+ void status(size_t& count, size_t& unseen);
+ shared_ptr <folderStatus> getStatus();
+
+ void expunge();
+
+ shared_ptr <folder> getParent();
+
+ shared_ptr <const store> getStore() const;
+ shared_ptr <store> getStore();
+
+
+ void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress = NULL
+ );
+
+ void fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options);
+
+ std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ );
+
+ int getFetchCapabilities() const;
+
+ std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid);
+
+private:
+
+ void registerMessage(POP3Message* msg);
+ void unregisterMessage(POP3Message* msg);
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+
+ weak_ptr <POP3Store> m_store;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ size_t m_messageCount;
+
+ typedef std::map <POP3Message*, size_t> MessageMap;
+ MessageMap m_messages;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp
new file mode 100644
index 0000000..9f2c49f
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3FolderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3FolderStatus::POP3FolderStatus()
+ : m_count(0),
+ m_unseen(0) {
+
+}
+
+
+POP3FolderStatus::POP3FolderStatus(const POP3FolderStatus& other)
+ : folderStatus(),
+ m_count(other.m_count),
+ m_unseen(other.m_unseen) {
+
+}
+
+
+size_t POP3FolderStatus::getMessageCount() const {
+
+ return m_count;
+}
+
+
+size_t POP3FolderStatus::getUnseenCount() const {
+
+ return m_unseen;
+}
+
+
+void POP3FolderStatus::setMessageCount(const size_t count) {
+
+ m_count = count;
+}
+
+
+void POP3FolderStatus::setUnseenCount(const size_t unseen) {
+
+ m_unseen = unseen;
+}
+
+
+shared_ptr <folderStatus> POP3FolderStatus::clone() const {
+
+ return make_shared <POP3FolderStatus>(*this);
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp
new file mode 100644
index 0000000..0ce413e
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/folderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+/** Holds the status of a POP3 folder.
+ */
+class VMIME_EXPORT POP3FolderStatus : public folderStatus {
+
+public:
+
+ POP3FolderStatus();
+ POP3FolderStatus(const POP3FolderStatus& other);
+
+ // Inherited from folderStatus
+ size_t getMessageCount() const;
+ size_t getUnseenCount() const;
+
+ shared_ptr <folderStatus> clone() const;
+
+
+ void setMessageCount(const size_t count);
+ void setUnseenCount(const size_t unseen);
+
+private:
+
+ size_t m_count;
+ size_t m_unseen;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Message.cpp b/vmime-master/src/vmime/net/pop3/POP3Message.cpp
new file mode 100644
index 0000000..8d6b7f5
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Message.cpp
@@ -0,0 +1,283 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Message.hpp"
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+#include "vmime/net/pop3/POP3Folder.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Message::POP3Message(
+ const shared_ptr <POP3Folder>& folder,
+ const size_t num
+)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1),
+ m_deleted(false) {
+
+ folder->registerMessage(this);
+}
+
+
+POP3Message::~POP3Message() {
+
+ try {
+
+ shared_ptr <POP3Folder> folder = m_folder.lock();
+
+ if (folder) {
+ folder->unregisterMessage(this);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void POP3Message::onFolderClosed() {
+
+ m_folder.reset();
+}
+
+
+size_t POP3Message::getNumber() const {
+
+ return m_num;
+}
+
+
+const message::uid POP3Message::getUID() const {
+
+ return m_uid;
+}
+
+
+size_t POP3Message::getSize() const {
+
+ if (m_size == static_cast <size_t>(-1)) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_size;
+}
+
+
+bool POP3Message::isExpunged() const {
+
+ return false;
+}
+
+
+int POP3Message::getFlags() const {
+
+ int flags = 0;
+
+ if (m_deleted) {
+ flags |= FLAG_DELETED;
+ }
+
+ return flags;
+}
+
+
+shared_ptr <const messageStructure> POP3Message::getStructure() const {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+shared_ptr <messageStructure> POP3Message::getStructure() {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+shared_ptr <const header> POP3Message::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_header;
+}
+
+
+void POP3Message::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool /* peek */
+) const {
+
+ shared_ptr <const POP3Folder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::illegal_state("Folder closed");
+ } else if (!folder->getStore()) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (start != 0 && length != static_cast <size_t>(-1)) {
+ throw exceptions::partial_fetch_not_supported();
+ }
+
+ // Emit the "RETR" command
+ shared_ptr <POP3Store> store = folder->m_store.lock();
+
+ POP3Command::RETR(m_num)->send(store->getConnection());
+
+ try {
+
+ POP3Response::readLargeResponse(
+ store->getConnection(), os, progress,
+ m_size == static_cast <size_t>(-1) ? 0 : m_size
+ );
+
+ } catch (exceptions::command_error& e) {
+
+ throw exceptions::command_error("RETR", e.response());
+ }
+}
+
+
+void POP3Message::extractPart(
+ const shared_ptr <const messagePart>& /* p */,
+ utility::outputStream& /* os */,
+ utility::progressListener* /* progress */,
+ const size_t /* start */,
+ const size_t /* length */,
+ const bool /* peek */
+) const {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Message::fetchPartHeader(const shared_ptr <messagePart>& /* p */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Message::fetch(
+ const shared_ptr <POP3Folder>& msgFolder,
+ const fetchAttributes& options
+) {
+
+ shared_ptr <POP3Folder> folder = m_folder.lock();
+
+ if (folder != msgFolder) {
+ throw exceptions::folder_not_found();
+ }
+
+ // STRUCTURE and FLAGS attributes are not supported by POP3
+ if (options.has(fetchAttributes::STRUCTURE | fetchAttributes::FLAGS)) {
+ throw exceptions::operation_not_supported();
+ }
+
+ // Check for the real need to fetch the full header
+ static const int optionsRequiringHeader =
+ fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FULL_HEADER | fetchAttributes::IMPORTANCE;
+
+ if (!options.has(optionsRequiringHeader)) {
+ return;
+ }
+
+ // No need to differenciate between ENVELOPE, CONTENT_INFO, ...
+ // since POP3 only permits to retrieve the whole header and not
+ // fields in particular.
+
+ // Emit the "TOP" command
+ shared_ptr <POP3Store> store = folder->m_store.lock();
+
+ POP3Command::TOP(m_num, 0)->send(store->getConnection());
+
+ try {
+
+ string buffer;
+ utility::outputStreamStringAdapter bufferStream(buffer);
+
+ POP3Response::readLargeResponse(
+ store->getConnection(),
+ bufferStream, /* progress */ NULL, /* predictedSize */ 0
+ );
+
+ m_header = make_shared <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();
+}
+
+
+shared_ptr <vmime::message> POP3Message::getParsedMessage() {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter os(oss);
+
+ extract(os);
+
+ shared_ptr <vmime::message> msg = make_shared <vmime::message>();
+ msg->parse(oss.str());
+
+ return msg;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Message.hpp b/vmime-master/src/vmime/net/pop3/POP3Message.hpp
new file mode 100644
index 0000000..3d6dc92
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Message.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Folder;
+
+
+/** POP3 message implementation.
+ */
+class VMIME_EXPORT POP3Message : public message {
+
+private:
+
+ friend class POP3Folder;
+
+ POP3Message(const POP3Message&);
+
+public:
+
+ POP3Message(const shared_ptr <POP3Folder>& folder, const size_t num);
+
+ ~POP3Message();
+
+
+ size_t getNumber() const;
+
+ const uid getUID() const;
+
+ size_t getSize() const;
+
+ bool isExpunged() const;
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const header> getHeader() const;
+
+ int getFlags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void fetchPartHeader(const shared_ptr <messagePart>& p);
+
+ shared_ptr <vmime::message> getParsedMessage();
+
+private:
+
+ void fetch(const shared_ptr <POP3Folder>& folder, const fetchAttributes& options);
+
+ void onFolderClosed();
+
+ weak_ptr <POP3Folder> m_folder;
+ size_t m_num;
+ uid m_uid;
+ size_t m_size;
+
+ bool m_deleted;
+
+ shared_ptr <header> m_header;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Response.cpp b/vmime-master/src/vmime/net/pop3/POP3Response.cpp
new file mode 100644
index 0000000..725841e
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Response.cpp
@@ -0,0 +1,504 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Response.hpp"
+#include "vmime/net/pop3/POP3Connection.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/inputStreamSocketAdapter.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Response::POP3Response(
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const shared_ptr <tracer>& tracer
+)
+ : m_socket(sok),
+ m_timeoutHandler(toh),
+ m_tracer(tracer) {
+
+}
+
+
+// static
+shared_ptr <POP3Response> POP3Response::readResponse(
+ const shared_ptr <POP3Connection>& conn
+) {
+
+ shared_ptr <POP3Response> resp = shared_ptr <POP3Response>(
+ new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())
+ );
+
+ string buffer;
+ resp->readResponseImpl(buffer, /* multiLine */ false);
+
+ resp->m_firstLine = buffer;
+ resp->m_code = getResponseCode(buffer);
+ stripResponseCode(buffer, resp->m_text);
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(buffer);
+ }
+
+ return resp;
+}
+
+
+// static
+shared_ptr <POP3Response> POP3Response::readMultilineResponse(
+ const shared_ptr <POP3Connection>& conn
+) {
+
+ shared_ptr <POP3Response> resp = shared_ptr <POP3Response>(
+ new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())
+ );
+
+ string buffer;
+ resp->readResponseImpl(buffer, /* multiLine */ true);
+
+ string firstLine, nextLines;
+ stripFirstLine(buffer, nextLines, &firstLine);
+
+ resp->m_firstLine = firstLine;
+ resp->m_code = getResponseCode(firstLine);
+ stripResponseCode(firstLine, resp->m_text);
+
+ std::istringstream iss(nextLines);
+ string line;
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(firstLine);
+ }
+
+ while (std::getline(iss, line, '\n')) {
+
+ line = utility::stringUtils::trim(line);
+ resp->m_lines.push_back(line);
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(line);
+ }
+ }
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(".");
+ }
+
+ return resp;
+}
+
+
+// static
+shared_ptr <POP3Response> POP3Response::readLargeResponse(
+ const shared_ptr <POP3Connection>& conn,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+) {
+
+ shared_ptr <POP3Response> resp = shared_ptr <POP3Response>(
+ new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())
+ );
+
+ string firstLine;
+ const size_t length = resp->readResponseImpl(firstLine, os, progress, predictedSize);
+
+ resp->m_firstLine = firstLine;
+ resp->m_code = getResponseCode(firstLine);
+ stripResponseCode(firstLine, resp->m_text);
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(firstLine);
+ resp->m_tracer->traceReceiveBytes(length - firstLine.length());
+ resp->m_tracer->traceReceive(".");
+ }
+
+ return resp;
+}
+
+
+bool POP3Response::isSuccess() const {
+
+ return m_code == CODE_OK;
+}
+
+
+const string POP3Response::getFirstLine() const {
+
+ return m_firstLine;
+}
+
+
+POP3Response::ResponseCode POP3Response::getCode() const {
+
+ return m_code;
+}
+
+
+const string POP3Response::getText() const {
+
+ return m_text;
+}
+
+
+const string POP3Response::getLineAt(const size_t pos) const {
+
+ return m_lines[pos];
+}
+
+
+size_t POP3Response::getLineCount() const {
+
+ return m_lines.size();
+}
+
+
+void POP3Response::readResponseImpl(string& buffer, const bool multiLine) {
+
+ bool foundTerminator = false;
+
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ buffer.clear();
+
+ char last1 = '\0', last2 = '\0';
+
+ for ( ; !foundTerminator ; ) {
+
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Receive data from the socket
+ string receiveBuffer;
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+
+ if (m_socket->getStatus() & socket::STATUS_WANT_WRITE) {
+ m_socket->waitForWrite();
+ } else {
+ m_socket->waitForRead();
+ }
+
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Check for transparent characters: '\n..' becomes '\n.'
+ const char 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 (size_t trans ;
+ string::npos != (trans = receiveBuffer.find("\n..")) ; ) {
+
+ receiveBuffer.replace(trans, 3, "\n.");
+ }
+
+ last1 = receiveBuffer[receiveBuffer.length() - 1];
+ last2 = static_cast <char>((receiveBuffer.length() >= 2) ? receiveBuffer[receiveBuffer.length() - 2] : 0);
+
+ // Append the data to the response buffer
+ buffer += receiveBuffer;
+
+ // Check for terminator string (and strip it if present)
+ foundTerminator = checkTerminator(buffer, multiLine);
+
+ // If there is an error (-ERR) when executing a command that
+ // requires a multi-line response, the error response will
+ // include only one line, so we stop waiting for a multi-line
+ // terminator and check for a "normal" one.
+ if (multiLine &&
+ !foundTerminator &&
+ buffer.length() >= 4 && buffer[0] == '-') {
+
+ foundTerminator = checkTerminator(buffer, false);
+ }
+ }
+}
+
+
+size_t POP3Response::readResponseImpl(
+ string& firstLine,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+) {
+
+ size_t 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()) {
+
+ // 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
+ byte_t buffer[65536];
+ const size_t read = is.read(buffer, sizeof(buffer));
+
+ if (read == 0) { // buffer is empty
+
+ if (m_socket->getStatus() & socket::STATUS_WANT_WRITE) {
+ m_socket->waitForWrite();
+ } else if (m_socket->getStatus() & socket::STATUS_WANT_READ) {
+ m_socket->waitForRead();
+ } else {
+ // Input stream needs more bytes to continue, but there
+ // is enough data into socket buffer. Do not waitForRead(),
+ // just retry read()ing on the stream.
+ }
+
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Notify progress
+ current += read;
+
+ if (progress) {
+ total = std::max(total, current);
+ progress->progress(current, total);
+ }
+
+ // If we don't have extracted the response code yet
+ if (!codeDone) {
+
+ vmime::utility::stringUtils::appendBytesToString(temp, buffer, read);
+
+ string responseData;
+
+ if (stripFirstLine(temp, responseData, &firstLine) == true) {
+
+ if (getResponseCode(firstLine) != CODE_OK) {
+ throw exceptions::command_error("?", firstLine);
+ }
+
+ codeDone = true;
+
+ os.write(responseData.data(), responseData.length());
+ temp.clear();
+
+ continue;
+ }
+
+ } else {
+
+ // Inject the data into the output stream
+ os.write(buffer, read);
+ }
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ return current;
+}
+
+
+// static
+bool POP3Response::stripFirstLine(
+ const string& buffer,
+ string& result,
+ string* firstLine
+) {
+
+ const size_t end = buffer.find('\n');
+
+ if (end != string::npos) {
+
+ if (firstLine) {
+ *firstLine = utility::stringUtils::trim(buffer.substr(0, end));
+ }
+
+ result = buffer.substr(end + 1);
+
+ return true;
+
+ } else {
+
+ if (firstLine) {
+ *firstLine = utility::stringUtils::trim(buffer);
+ }
+
+ result = "";
+
+ return false;
+ }
+}
+
+
+// static
+POP3Response::ResponseCode POP3Response::getResponseCode(const string& buffer) {
+
+ if (buffer.length() >= 2) {
+
+ // +[space]
+ if (buffer[0] == '+' &&
+ (buffer[1] == ' ' || buffer[1] == '\t')) {
+
+ return CODE_READY;
+ }
+
+ // +OK
+ if (buffer.length() >= 3) {
+
+ if (buffer[0] == '+' &&
+ (buffer[1] == 'O' || buffer[1] == 'o') &&
+ (buffer[2] == 'K' || buffer[1] == 'k')) {
+
+ return CODE_OK;
+ }
+ }
+ }
+
+ // -ERR or whatever
+ return CODE_ERR;
+}
+
+
+// static
+void POP3Response::stripResponseCode(const string& buffer, string& result) {
+
+ const size_t pos = buffer.find_first_of(" \t");
+
+ if (pos != string::npos) {
+ result = buffer.substr(pos + 1);
+ } else {
+ result = buffer;
+ }
+}
+
+
+// static
+bool POP3Response::checkTerminator(string& buffer, const bool multiLine) {
+
+ // Multi-line response
+ if (multiLine) {
+
+ static const string term1("\r\n.\r\n");
+ static const string term2("\n.\n");
+
+ return checkOneTerminator(buffer, term1) ||
+ checkOneTerminator(buffer, term2);
+
+ // Normal response
+ } else {
+
+ static const string term1("\r\n");
+ static const string term2("\n");
+
+ return checkOneTerminator(buffer, term1) ||
+ checkOneTerminator(buffer, term2);
+ }
+
+ return false;
+}
+
+
+// static
+bool POP3Response::checkOneTerminator(string& buffer, const string& term) {
+
+ if (buffer.length() >= term.length() &&
+ std::equal(buffer.end() - term.length(), buffer.end(), term.begin())) {
+
+ buffer.erase(buffer.end() - term.length(), buffer.end());
+ return true;
+ }
+
+ return false;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3Response.hpp b/vmime-master/src/vmime/net/pop3/POP3Response.hpp
new file mode 100644
index 0000000..69f8d5d
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Response.hpp
@@ -0,0 +1,194 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
+#define VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/utility/outputStream.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/tracer.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class timeoutHandler;
+
+
+namespace pop3 {
+
+
+class POP3Connection;
+
+
+/** A POP3 response, as sent by the server.
+ */
+class VMIME_EXPORT POP3Response : public object {
+
+public:
+
+ /** Possible response codes. */
+ enum ResponseCode {
+ CODE_OK = 0,
+ CODE_READY,
+ CODE_ERR
+ };
+
+
+ /** Receive and parse a POP3 response from the
+ * specified connection.
+ *
+ * @param conn connection from which to read
+ * @return POP3 response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <POP3Response> readResponse(const shared_ptr <POP3Connection>& conn);
+
+ /** Receive and parse a multiline POP3 response from
+ * the specified connection.
+ *
+ * @param conn connection from which to read
+ * @return POP3 response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <POP3Response> readMultilineResponse(const shared_ptr <POP3Connection>& conn);
+
+ /** Receive and parse a large POP3 response (eg. message data)
+ * from the specified connection.
+ *
+ * @param conn connection from which to read
+ * @param os output stream to which response data will be written
+ * @param progress progress listener (can be NULL)
+ * @param predictedSize estimated size of response data (in bytes)
+ * @return POP3 response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <POP3Response> readLargeResponse(
+ const shared_ptr <POP3Connection>& conn,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+ );
+
+
+ /** Returns whether the response is successful ("OK").
+ *
+ * @return true if the response if successful, false otherwise
+ */
+ bool isSuccess() const;
+
+ /** Return the POP3 response code.
+ *
+ * @return response code
+ */
+ ResponseCode getCode() const;
+
+ /** Return the POP3 response text (first line).
+ *
+ * @return response text
+ */
+ const string getText() const;
+
+ /** Return the first POP3 response line.
+ *
+ * @return first response line
+ */
+ const string getFirstLine() const;
+
+ /** Return the response line at the specified position.
+ *
+ * @param pos line index
+ * @return line at the specified index
+ */
+ const string getLineAt(const size_t pos) const;
+
+ /** Return the number of lines in the response.
+ *
+ * @return number of lines in the response
+ */
+ size_t getLineCount() const;
+
+private:
+
+ POP3Response(
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const shared_ptr <tracer>& tracer
+ );
+
+ void readResponseImpl(string& buffer, const bool multiLine);
+
+ size_t readResponseImpl(
+ string& firstLine,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+ );
+
+
+ static bool stripFirstLine(const string& buffer, string& result, string* firstLine);
+
+ static ResponseCode getResponseCode(const string& buffer);
+
+ static void stripResponseCode(const string& buffer, string& result);
+
+ static bool checkTerminator(string& buffer, const bool multiLine);
+ static bool checkOneTerminator(string& buffer, const string& term);
+
+
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ string m_firstLine;
+ ResponseCode m_code;
+ string m_text;
+
+ std::vector <string> m_lines;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3SStore.cpp b/vmime-master/src/vmime/net/pop3/POP3SStore.cpp
new file mode 100644
index 0000000..81a50bc
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3SStore.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3SStore.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3SStore::POP3SStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : POP3Store(sess, auth, true) {
+
+}
+
+
+POP3SStore::~POP3SStore() {
+
+}
+
+
+const string POP3SStore::getProtocolName() const {
+
+ return "pop3s";
+}
+
+
+
+// Service infos
+
+POP3ServiceInfos POP3SStore::sm_infos(true);
+
+
+const serviceInfos& POP3SStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& POP3SStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3SStore.hpp b/vmime-master/src/vmime/net/pop3/POP3SStore.hpp
new file mode 100644
index 0000000..76a6ee1
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3SStore.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3SSTORE_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3SSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Store.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+/** POP3S store service.
+ */
+class VMIME_EXPORT POP3SStore : public POP3Store {
+
+public:
+
+ POP3SStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~POP3SStore();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+private:
+
+ static POP3ServiceInfos sm_infos;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3SSTORE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp
new file mode 100644
index 0000000..4deee74
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp
@@ -0,0 +1,142 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3ServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3ServiceInfos::POP3ServiceInfos(const bool pop3s)
+ : m_pop3s(pop3s) {
+
+}
+
+
+const string POP3ServiceInfos::getPropertyPrefix() const {
+
+ if (m_pop3s) {
+ return "store.pop3s.";
+ } else {
+ return "store.pop3.";
+ }
+}
+
+
+const POP3ServiceInfos::props& POP3ServiceInfos::getProperties() const {
+
+ static props pop3Props = {
+ // POP3-specific options
+ property("options.apop", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.apop.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "110"),
+ };
+
+ static props pop3sProps = {
+
+ // POP3-specific options
+ property("options.apop", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.apop.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "995"),
+ };
+
+ return m_pop3s ? pop3sProps : pop3Props;
+}
+
+
+const std::vector <serviceInfos::property> POP3ServiceInfos::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);
+#if VMIME_HAVE_SASL_SUPPORT
+ list.push_back(p.PROPERTY_OPTIONS_SASL);
+ list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ list.push_back(p.PROPERTY_AUTH_USERNAME);
+ list.push_back(p.PROPERTY_AUTH_PASSWORD);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (!m_pop3s) {
+ list.push_back(p.PROPERTY_CONNECTION_TLS);
+ list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED);
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ list.push_back(p.PROPERTY_SERVER_ADDRESS);
+ list.push_back(p.PROPERTY_SERVER_PORT);
+
+ return list;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp
new file mode 100644
index 0000000..590a6be
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp
@@ -0,0 +1,91 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3SERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3SERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+/** Information about POP3 service.
+ */
+class VMIME_EXPORT POP3ServiceInfos : public serviceInfos {
+
+public:
+
+ POP3ServiceInfos(const bool pop3s);
+
+ struct props {
+ // POP3-specific options
+ serviceInfos::property PROPERTY_OPTIONS_APOP;
+ serviceInfos::property PROPERTY_OPTIONS_APOP_FALLBACK;
+#if VMIME_HAVE_SASL_SUPPORT
+ serviceInfos::property PROPERTY_OPTIONS_SASL;
+ serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ serviceInfos::property PROPERTY_AUTH_USERNAME;
+ serviceInfos::property PROPERTY_AUTH_PASSWORD;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ serviceInfos::property PROPERTY_CONNECTION_TLS;
+ serviceInfos::property PROPERTY_CONNECTION_TLS_REQUIRED;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ serviceInfos::property PROPERTY_SERVER_ADDRESS;
+ serviceInfos::property PROPERTY_SERVER_PORT;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+
+private:
+
+ const bool m_pop3s;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3SERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Store.cpp b/vmime-master/src/vmime/net/pop3/POP3Store.cpp
new file mode 100644
index 0000000..b06640f
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Store.cpp
@@ -0,0 +1,262 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3Folder.hpp"
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Store::POP3Store(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured
+)
+ : store(sess, getInfosInstance(), auth),
+ m_isPOP3S(secured) {
+
+}
+
+
+POP3Store::~POP3Store() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string POP3Store::getProtocolName() const {
+
+ return "pop3";
+}
+
+
+shared_ptr <folder> POP3Store::getDefaultFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <POP3Folder>(
+ new POP3Folder(
+ folder::path(folder::path::component("INBOX")),
+ dynamicCast <POP3Store>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> POP3Store::getRootFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <POP3Folder>(
+ new POP3Folder(
+ folder::path(),
+ dynamicCast <POP3Store>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> POP3Store::getFolder(const folder::path& path) {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <POP3Folder>(
+ new POP3Folder(
+ path,
+ dynamicCast <POP3Store>(shared_from_this())
+ )
+ );
+}
+
+
+bool POP3Store::isValidFolderName(const folder::path::component& /* name */) const {
+
+ return true;
+}
+
+
+void POP3Store::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ m_connection = make_shared <POP3Connection>(
+ dynamicCast <POP3Store>(shared_from_this()), getAuthenticator()
+ );
+
+ m_connection->connect();
+}
+
+
+bool POP3Store::isPOP3S() const {
+
+ return m_isPOP3S;
+}
+
+
+bool POP3Store::isConnected() const {
+
+ return m_connection && m_connection->isConnected();
+}
+
+
+bool POP3Store::isSecuredConnection() const {
+
+ if (!m_connection) {
+ return false;
+ }
+
+ return m_connection->isSecuredConnection();
+}
+
+
+shared_ptr <connectionInfos> POP3Store::getConnectionInfos() const {
+
+ if (!m_connection) {
+ return null;
+ }
+
+ return m_connection->getConnectionInfos();
+}
+
+
+shared_ptr <POP3Connection> POP3Store::getConnection() {
+
+ return m_connection;
+}
+
+
+void POP3Store::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ for (std::list <POP3Folder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it) {
+
+ (*it)->onStoreDisconnected();
+ }
+
+ m_folders.clear();
+
+
+ m_connection->disconnect();
+ m_connection = null;
+}
+
+
+void POP3Store::noop() {
+
+ if (!m_connection) {
+ throw exceptions::not_connected();
+ }
+
+ POP3Command::NOOP()->send(m_connection);
+
+ shared_ptr <POP3Response> response = POP3Response::readResponse(m_connection);
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("NOOP", response->getFirstLine());
+ }
+}
+
+
+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);
+ }
+}
+
+
+int POP3Store::getCapabilities() const {
+
+ return CAPABILITY_DELETE_MESSAGE;
+}
+
+
+
+// Service infos
+
+POP3ServiceInfos POP3Store::sm_infos(false);
+
+
+const serviceInfos& POP3Store::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& POP3Store::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Store.hpp b/vmime-master/src/vmime/net/pop3/POP3Store.hpp
new file mode 100644
index 0000000..140a1ab
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Store.hpp
@@ -0,0 +1,120 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/store.hpp"
+
+#include "vmime/net/pop3/POP3ServiceInfos.hpp"
+#include "vmime/net/pop3/POP3Connection.hpp"
+
+#include "vmime/utility/stream.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Folder;
+class POP3Command;
+class POP3Response;
+
+
+/** POP3 store service.
+ */
+class VMIME_EXPORT POP3Store : public store {
+
+ friend class POP3Folder;
+ friend class POP3Message;
+
+public:
+
+ POP3Store(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured = false
+ );
+
+ ~POP3Store();
+
+ const string getProtocolName() const;
+
+ shared_ptr <folder> getDefaultFolder();
+ shared_ptr <folder> getRootFolder();
+ shared_ptr <folder> getFolder(const folder::path& path);
+
+ bool isValidFolderName(const folder::path::component& name) const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ int getCapabilities() const;
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+ shared_ptr <POP3Connection> getConnection();
+
+ bool isPOP3S() const;
+
+private:
+
+ shared_ptr <POP3Connection> m_connection;
+
+
+ void registerFolder(POP3Folder* folder);
+ void unregisterFolder(POP3Folder* folder);
+
+ std::list <POP3Folder*> m_folders;
+
+
+ const bool m_isPOP3S;
+
+
+ // Service infos
+ static POP3ServiceInfos sm_infos;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Utils.cpp b/vmime-master/src/vmime/net/pop3/POP3Utils.cpp
new file mode 100644
index 0000000..b38161e
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Utils.cpp
@@ -0,0 +1,135 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Utils.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+// static
+void POP3Utils::parseMultiListOrUidlResponse(
+ const shared_ptr <POP3Response>& response,
+ std::map <size_t, string>& result
+) {
+
+ std::map <size_t, string> ids;
+
+ for (size_t i = 0, n = response->getLineCount() ; i < n ; ++i) {
+
+ string line = response->getLineAt(i);
+ string::iterator it = line.begin();
+
+ while (it != line.end() && (*it == ' ' || *it == '\t')) {
+ ++it;
+ }
+
+ if (it != line.end()) {
+
+ size_t 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 <size_t, string>::value_type(number, string(it, line.end())));
+ }
+ }
+ }
+}
+
+
+
+class POP3MessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ POP3MessageSetEnumerator(const size_t msgCount)
+ : m_msgCount(msgCount) {
+
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ size_t last = range.getLast();
+
+ if (last == size_t(-1)) {
+ last = m_msgCount;
+ }
+
+ for (size_t i = range.getFirst() ; i <= last ; ++i) {
+ list.push_back(i);
+ }
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) {
+
+ // Not supported
+ }
+
+public:
+
+ std::vector <size_t> list;
+
+private:
+
+ size_t m_msgCount;
+};
+
+
+// static
+const std::vector <size_t> POP3Utils::messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+) {
+
+ POP3MessageSetEnumerator en(msgCount);
+ msgs.enumerate(en);
+
+ return en.list;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Utils.hpp b/vmime-master/src/vmime/net/pop3/POP3Utils.hpp
new file mode 100644
index 0000000..09d15d5
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Utils.hpp
@@ -0,0 +1,92 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3UTILS_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3UTILS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include <map>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Response;
+
+
+class VMIME_EXPORT POP3Utils {
+
+public:
+
+ /** Parse a response of type ([integer] [string] \n)*.
+ * This is used in LIST or UIDL commands:
+ *
+ * C: UIDL
+ * S: +OK
+ * S: 1 whqtswO00WBw418f9t5JxYwZ
+ * S: 2 QhdPYR:00WBw1Ph7x7
+ * S: .
+ *
+ * @param response raw response string as returned by the server
+ * @param result points to an associative array which maps a message
+ * number to its corresponding data (either UID or size)
+ */
+ static void parseMultiListOrUidlResponse(
+ const shared_ptr <POP3Response>& response,
+ std::map <size_t, string>& result
+ );
+
+ /** Returns a list of message numbers given a message set.
+ *
+ * @param msgs message set
+ * @param msgCount number of messages in folder
+ * @return list of message numbers
+ */
+ static const std::vector <size_t> messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+ );
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3UTILS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/pop3/pop3.hpp b/vmime-master/src/vmime/net/pop3/pop3.hpp
new file mode 100644
index 0000000..ced3a97
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/pop3.hpp
@@ -0,0 +1,35 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3_HPP_INCLUDED
+
+
+#include "vmime/net/pop3/POP3Folder.hpp"
+#include "vmime/net/pop3/POP3FolderStatus.hpp"
+#include "vmime/net/pop3/POP3Message.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3SStore.hpp"
+
+
+#endif // VMIME_NET_POP3_POP3_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/securedConnectionInfos.hpp b/vmime-master/src/vmime/net/securedConnectionInfos.hpp
new file mode 100644
index 0000000..6025801
--- /dev/null
+++ b/vmime-master/src/vmime/net/securedConnectionInfos.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SECUREDCONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_SECUREDCONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/connectionInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Information about the secured connection used by a service.
+ */
+class VMIME_EXPORT securedConnectionInfos : public connectionInfos {
+
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SECUREDCONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmail.hpp b/vmime-master/src/vmime/net/sendmail/sendmail.hpp
new file mode 100644
index 0000000..a8d1412
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmail.hpp
@@ -0,0 +1,31 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SENDMAIL_SENDMAIL_HPP_INCLUDED
+#define VMIME_NET_SENDMAIL_SENDMAIL_HPP_INCLUDED
+
+
+#include "vmime/net/sendmail/sendmailTransport.hpp"
+
+
+#endif // VMIME_NET_SENDMAIL_SENDMAIL_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp
new file mode 100644
index 0000000..b865446
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/sendmail/sendmailServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+sendmailServiceInfos::sendmailServiceInfos() {
+
+}
+
+
+const string sendmailServiceInfos::getPropertyPrefix() const {
+
+ return "transport.sendmail.";
+}
+
+
+const sendmailServiceInfos::props& sendmailServiceInfos::getProperties() const {
+
+ static props sendmailProps = {
+ // Path to sendmail (override default)
+ property("binpath", serviceInfos::property::TYPE_STRING, string(VMIME_SENDMAIL_PATH))
+ };
+
+ return sendmailProps;
+}
+
+
+const std::vector <serviceInfos::property> sendmailServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ list.push_back(p.PROPERTY_BINPATH);
+
+ return list;
+}
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp
new file mode 100644
index 0000000..bfec2e0
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SENDMAIL_SENDMAILSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_SENDMAIL_SENDMAILSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+/** Information about sendmail service.
+ */
+class VMIME_EXPORT sendmailServiceInfos : public serviceInfos {
+
+public:
+
+ sendmailServiceInfos();
+
+ struct props {
+ serviceInfos::property PROPERTY_BINPATH;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+};
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+#endif // VMIME_NET_SENDMAIL_SENDMAILSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp b/vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp
new file mode 100644
index 0000000..7010fd8
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp
@@ -0,0 +1,244 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/sendmail/sendmailTransport.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+#include "vmime/message.hpp"
+#include "vmime/mailboxList.hpp"
+
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/childProcess.hpp"
+
+#include "vmime/utility/streamUtils.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#include "vmime/config.hpp"
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const sendmailServiceInfos&>(getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (getInfos().hasProperty(getSession(), \
+ dynamic_cast <const sendmailServiceInfos&>(getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+sendmailTransport::sendmailTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : transport(sess, getInfosInstance(), auth),
+ m_connected(false) {
+
+}
+
+
+sendmailTransport::~sendmailTransport() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+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;
+}
+
+
+bool sendmailTransport::isConnected() const {
+
+ return m_connected;
+}
+
+
+bool sendmailTransport::isSecuredConnection() const {
+
+ return false;
+}
+
+
+shared_ptr <connectionInfos> sendmailTransport::getConnectionInfos() const {
+
+ return make_shared <defaultConnectionInfos>("localhost", static_cast <port_t>(0));
+}
+
+
+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 size_t size,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& /*dsnAttrs*/
+) {
+
+ // 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");
+
+ if (!sender.isEmpty()) {
+ args.push_back(expeditor.getEmail().generate());
+ } else {
+ args.push_back(sender.getEmail().generate());
+ }
+
+ args.push_back("--");
+
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+ args.push_back(recipients.getMailboxAt(i)->getEmail().generate());
+ }
+
+ // 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 size_t size,
+ utility::progressListener* progress
+) {
+
+ const utility::file::path path = vmime::platform::getHandler()->
+ getFileSystemFactory()->stringToPath(m_sendmailPath);
+
+ shared_ptr <utility::childProcess> proc =
+ vmime::platform::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
+
+sendmailServiceInfos sendmailTransport::sm_infos;
+
+
+const serviceInfos& sendmailTransport::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& sendmailTransport::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp b/vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp
new file mode 100644
index 0000000..ce2cfe9
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
+#define VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/transport.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/net/sendmail/sendmailServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+/** Sendmail local transport service.
+ */
+class VMIME_EXPORT sendmailTransport : public transport {
+
+public:
+
+ sendmailTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~sendmailTransport();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ void send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+private:
+
+ void internalDisconnect();
+
+ void internalSend(
+ const std::vector <string>& args,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress
+ );
+
+
+ string m_sendmailPath;
+
+ bool m_connected;
+
+
+ // Service infos
+ static sendmailServiceInfos sm_infos;
+};
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+#endif // VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/service.cpp b/vmime-master/src/vmime/net/service.cpp
new file mode 100644
index 0000000..b43c3e2
--- /dev/null
+++ b/vmime-master/src/vmime/net/service.cpp
@@ -0,0 +1,170 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/service.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/net/defaultTimeoutHandler.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/defaultSASLAuthenticator.hpp"
+#else
+ #include "vmime/security/defaultAuthenticator.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/security/cert/defaultCertificateVerifier.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+namespace vmime {
+namespace net {
+
+
+service::service(
+ const shared_ptr <session>& sess,
+ const serviceInfos& /* infos */,
+ const shared_ptr <security::authenticator>& auth
+)
+ : m_session(sess),
+ m_auth(auth) {
+
+ if (!auth) {
+
+#if VMIME_HAVE_SASL_SUPPORT
+ m_auth = make_shared <security::sasl::defaultSASLAuthenticator>();
+#else
+ m_auth = make_shared <security::defaultAuthenticator>();
+#endif // VMIME_HAVE_SASL_SUPPORT
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+ m_certVerifier = make_shared <security::cert::defaultCertificateVerifier>();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ m_socketFactory = platform::getHandler()->getSocketFactory();
+
+ m_toHandlerFactory = make_shared <defaultTimeoutHandlerFactory>();
+}
+
+
+service::~service() {
+
+}
+
+
+shared_ptr <const session> service::getSession() const {
+
+ return m_session;
+}
+
+
+shared_ptr <session> service::getSession() {
+
+ return m_session;
+}
+
+
+shared_ptr <const security::authenticator> service::getAuthenticator() const {
+
+ return m_auth;
+}
+
+
+shared_ptr <security::authenticator> service::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+void service::setAuthenticator(const shared_ptr <security::authenticator>& auth) {
+
+ m_auth = auth;
+}
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void service::setCertificateVerifier(const shared_ptr <security::cert::certificateVerifier>& cv) {
+
+ m_certVerifier = cv;
+}
+
+
+shared_ptr <security::cert::certificateVerifier> service::getCertificateVerifier() {
+
+ return m_certVerifier;
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+void service::setSocketFactory(const shared_ptr <socketFactory>& sf) {
+
+ m_socketFactory = sf;
+}
+
+
+shared_ptr <socketFactory> service::getSocketFactory() {
+
+ return m_socketFactory;
+}
+
+
+void service::setTracerFactory(const shared_ptr <tracerFactory>& tf) {
+
+ m_tracerFactory = tf;
+}
+
+
+shared_ptr <tracerFactory> service::getTracerFactory() {
+
+ return m_tracerFactory;
+}
+
+
+void service::setTimeoutHandlerFactory(const shared_ptr <timeoutHandlerFactory>& thf) {
+
+ m_toHandlerFactory = thf;
+}
+
+
+shared_ptr <timeoutHandlerFactory> service::getTimeoutHandlerFactory() {
+
+ return m_toHandlerFactory;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/service.hpp b/vmime-master/src/vmime/net/service.hpp
new file mode 100644
index 0000000..a1869de
--- /dev/null
+++ b/vmime-master/src/vmime/net/service.hpp
@@ -0,0 +1,239 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SERVICE_HPP_INCLUDED
+#define VMIME_NET_SERVICE_HPP_INCLUDED
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/session.hpp"
+
+#include "vmime/net/serviceInfos.hpp"
+#include "vmime/net/connectionInfos.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/security/cert/certificateVerifier.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Base class for messaging services.
+ */
+class VMIME_EXPORT service : public object, public enable_shared_from_this <service> {
+
+protected:
+
+ service(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::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 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
+ */
+ shared_ptr <const session> getSession() const;
+
+ /** Return the session object associated with this service instance.
+ *
+ * @return session object
+ */
+ shared_ptr <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 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
+ */
+ shared_ptr <const security::authenticator> getAuthenticator() const;
+
+ /** Return the authenticator object used with this service instance.
+ *
+ * @return authenticator object
+ */
+ shared_ptr <security::authenticator> getAuthenticator();
+
+ /** Set the authenticator object used with this service instance.
+ *
+ * @param auth authenticator object
+ */
+ void setAuthenticator(const shared_ptr <security::authenticator>& auth);
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ /** Set the object responsible for verifying certificates when
+ * using secured connections (TLS/SSL).
+ */
+ void setCertificateVerifier(const shared_ptr <security::cert::certificateVerifier>& cv);
+
+ /** Get the object responsible for verifying certificates when
+ * using secured connections (TLS/SSL).
+ */
+ shared_ptr <security::cert::certificateVerifier> getCertificateVerifier();
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ /** Set the factory used to create socket objects for this
+ * service.
+ *
+ * @param sf socket factory
+ */
+ void setSocketFactory(const shared_ptr <socketFactory>& sf);
+
+ /** Return the factory used to create socket objects for this
+ * service.
+ *
+ * @return socket factory
+ */
+ shared_ptr <socketFactory> getSocketFactory();
+
+ /** Set the factory used to create timeoutHandler objects for
+ * this service. By default, the defaultTimeoutHandler class
+ * is used. Not all services support timeout handling.
+ *
+ * @param thf timeoutHandler factory
+ */
+ void setTimeoutHandlerFactory(const shared_ptr <timeoutHandlerFactory>& thf);
+
+ /** Return the factory used to create timeoutHandler objects for
+ * this service.
+ *
+ * @return timeoutHandler factory
+ */
+ shared_ptr <timeoutHandlerFactory> getTimeoutHandlerFactory();
+
+
+ void setTracerFactory(const shared_ptr <tracerFactory>& tf);
+
+ shared_ptr <tracerFactory> getTracerFactory();
+
+ /** 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;
+ }
+
+ /** Check whether the connection is secured.
+ *
+ * @return true if the connection is secured, false otherwise
+ */
+ virtual bool isSecuredConnection() const = 0;
+
+ /** Get information about the connection.
+ *
+ * @return information about the connection
+ */
+ virtual shared_ptr <connectionInfos> getConnectionInfos() const = 0;
+
+private:
+
+ shared_ptr <session> m_session;
+ shared_ptr <security::authenticator> m_auth;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ shared_ptr <security::cert::certificateVerifier> m_certVerifier;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ shared_ptr <socketFactory> m_socketFactory;
+ shared_ptr <timeoutHandlerFactory> m_toHandlerFactory;
+ shared_ptr <tracerFactory> m_tracerFactory;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SERVICE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/serviceFactory.cpp b/vmime-master/src/vmime/net/serviceFactory.cpp
new file mode 100644
index 0000000..72b96fe
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceFactory.cpp
@@ -0,0 +1,157 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/serviceFactory.hpp"
+#include "vmime/net/service.hpp"
+
+#include "vmime/exception.hpp"
+
+#include "vmime/net/builtinServices.inl"
+
+
+namespace vmime {
+namespace net {
+
+
+serviceFactory::serviceFactory() {
+
+}
+
+
+serviceFactory::~serviceFactory() {
+
+}
+
+
+shared_ptr <serviceFactory> serviceFactory::getInstance() {
+
+ static serviceFactory instance;
+ return shared_ptr <serviceFactory>(&instance, noop_shared_ptr_deleter <serviceFactory>());
+}
+
+
+shared_ptr <service> serviceFactory::create(
+ const shared_ptr <session>& sess,
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <const registeredService> rserv = getServiceByProtocol(protocol);
+
+ if (!rserv) {
+ throw exceptions::no_factory_available("No service is registered for protocol '" + protocol + "'.");
+ }
+
+ return rserv->create(sess, auth);
+}
+
+
+shared_ptr <service> serviceFactory::create(
+ const shared_ptr <session>& sess,
+ const utility::url& u,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <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;
+}
+
+
+shared_ptr <const serviceFactory::registeredService> serviceFactory::getServiceByProtocol(const string& protocol) const {
+
+ const string name(utility::stringUtils::toLower(protocol));
+
+ for (std::vector <shared_ptr <registeredService> >::const_iterator it = m_services.begin() ;
+ it != m_services.end() ; ++it) {
+
+ if ((*it)->getName() == name) {
+ return (*it);
+ }
+ }
+
+ return null;
+}
+
+
+size_t serviceFactory::getServiceCount() const {
+
+ return m_services.size();
+}
+
+
+shared_ptr <const serviceFactory::registeredService> serviceFactory::getServiceAt(const size_t pos) const {
+
+ return m_services[pos];
+}
+
+
+const std::vector <shared_ptr <const serviceFactory::registeredService> > serviceFactory::getServiceList() const {
+
+ std::vector <shared_ptr <const registeredService> > res;
+
+ for (std::vector <shared_ptr <registeredService> >::const_iterator it = m_services.begin() ;
+ it != m_services.end() ; ++it) {
+
+ res.push_back(*it);
+ }
+
+ return (res);
+}
+
+
+void serviceFactory::registerService(const shared_ptr <registeredService>& reg) {
+
+ m_services.push_back(reg);
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/serviceFactory.hpp b/vmime-master/src/vmime/net/serviceFactory.hpp
new file mode 100644
index 0000000..8911e08
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceFactory.hpp
@@ -0,0 +1,168 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
+#define VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <map>
+
+#include "vmime/types.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/url.hpp"
+
+#include "vmime/net/service.hpp"
+#include "vmime/net/serviceInfos.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class session;
+
+
+/** A factory to create 'service' objects for a specified protocol.
+ */
+
+class VMIME_EXPORT serviceFactory {
+
+private:
+
+ serviceFactory();
+ ~serviceFactory();
+
+public:
+
+ static shared_ptr <serviceFactory> getInstance();
+
+ /** Information about a registered service. */
+ class registeredService : public object {
+
+ friend class serviceFactory;
+
+ protected:
+
+ virtual ~registeredService() { }
+
+ public:
+
+ virtual shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ ) const = 0;
+
+ virtual int getType() const = 0;
+ virtual const string& getName() const = 0;
+ virtual const serviceInfos& getInfos() const = 0;
+ };
+
+
+ /** Register a new service by its protocol name.
+ *
+ * @param reg service registration infos
+ */
+ void registerService(const shared_ptr <registeredService>& reg);
+
+ /** 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, or NULL if no service
+ * is registered for this protocol
+ */
+ shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const string& protocol,
+ const shared_ptr <security::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 or NULL if no service
+ * is registered for this protocol
+ */
+ shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const utility::url& u,
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Return information about a registered protocol.
+ *
+ * @param protocol protocol name
+ * @return information about this protocol, or NULL if no service is registered
+ * for this protocol
+ */
+ shared_ptr <const registeredService> getServiceByProtocol(const string& protocol) const;
+
+ /** Return the number of registered services.
+ *
+ * @return number of registered services
+ */
+ size_t 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
+ */
+ shared_ptr <const registeredService> getServiceAt(const size_t pos) const;
+
+ /** Return a list of all registered services.
+ *
+ * @return list of registered services
+ */
+ const std::vector <shared_ptr <const registeredService> > getServiceList() const;
+
+private:
+
+ std::vector <shared_ptr <registeredService> > m_services;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/serviceInfos.cpp b/vmime-master/src/vmime/net/serviceInfos.cpp
new file mode 100644
index 0000000..2c7b044
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceInfos.cpp
@@ -0,0 +1,198 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#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::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::AUTH_ACCESS_TOKEN(
+ "auth.accesstoken",
+ serviceInfos::property::TYPE_STRING
+);
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+const serviceInfos::property serviceInfos::property::CONNECTION_TLS(
+ "connection.tls",
+ serviceInfos::property::TYPE_BOOLEAN,
+ "false"
+);
+
+const serviceInfos::property serviceInfos::property::CONNECTION_TLS_REQUIRED(
+ "connection.tls.required",
+ serviceInfos::property::TYPE_BOOLEAN,
+ "false"
+);
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+
+// serviceInfos
+
+serviceInfos::serviceInfos() {
+
+}
+
+
+serviceInfos::serviceInfos(const serviceInfos&) {
+
+}
+
+
+serviceInfos& serviceInfos::operator=(const serviceInfos&) {
+
+ return *this;
+}
+
+
+serviceInfos::~serviceInfos() {
+
+}
+
+
+bool serviceInfos::hasProperty(const shared_ptr <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;
+}
+
+
+serviceInfos::property::Types serviceInfos::property::getType() const {
+
+ return m_type;
+}
+
+
+int serviceInfos::property::getFlags() const {
+
+ return m_flags;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/serviceInfos.hpp b/vmime-master/src/vmime/net/serviceInfos.hpp
new file mode 100644
index 0000000..1c4ac99
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceInfos.hpp
@@ -0,0 +1,263 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_SERVICEINFOS_HPP_INCLUDED
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/session.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Stores information about a messaging service.
+ */
+class VMIME_EXPORT serviceInfos {
+
+ friend class serviceFactory;
+
+protected:
+
+ serviceInfos();
+ serviceInfos(const serviceInfos&);
+
+private:
+
+ serviceInfos& operator=(const serviceInfos&);
+
+public:
+
+ virtual ~serviceInfos();
+
+
+ /** A service property.
+ */
+ class VMIME_EXPORT 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 '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 'auth.accesstoken' which is the
+ * access token used to authenticate with the server. */
+ static const property AUTH_ACCESS_TOKEN;
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ /** The common property 'connection.tls': this is used to
+ * start a secured connection if it is supported by the
+ * server (STARTTLS extension).
+ */
+ static const property CONNECTION_TLS;
+
+ /** The common property 'connection.tls.required' should be
+ * set to 'true' to make the connection process fail if the
+ * server can't start a secured connection (no effect if
+ * 'connection.tls' is not set to 'true').
+ */
+ static const property CONNECTION_TLS_REQUIRED;
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+ /** Value types.
+ */
+ enum Types {
+ TYPE_INTEGER, /*< Integer number. */
+ TYPE_STRING, /*< Character string. */
+ TYPE_BOOLEAN, /*< 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
+ */
+ Types getType() const;
+
+ /** Return the attributes of the property (see
+ * serviceInfos::property::Types constants).
+ *
+ * @return property attributes
+ */
+ 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(const shared_ptr <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
+ */
+ bool hasProperty(const shared_ptr <session>& s, const property& p) const;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SERVICEINFOS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/serviceRegistration.inl b/vmime-master/src/vmime/net/serviceRegistration.inl
new file mode 100644
index 0000000..9365199
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceRegistration.inl
@@ -0,0 +1,105 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/net/serviceFactory.hpp"
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+namespace vmime {
+namespace net {
+
+
+template <class S>
+class registeredServiceImpl : public serviceFactory::registeredService {
+
+public:
+
+ registeredServiceImpl(
+ const string& name,
+ const int type
+ )
+ : m_type(type),
+ m_name(name),
+ m_servInfos(S::getInfosInstance()) {
+
+ }
+
+ shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ ) const {
+
+ return make_shared <S>(sess, auth);
+ }
+
+ const serviceInfos& getInfos() const {
+
+ return m_servInfos;
+ }
+
+ const string& getName() const {
+
+ return m_name;
+ }
+
+ int getType() const {
+
+ return m_type;
+ }
+
+private:
+
+ const int m_type;
+ const string m_name;
+ const serviceInfos& m_servInfos;
+};
+
+
+// Basic service registerer
+template <class S>
+class serviceRegisterer {
+
+public:
+
+ serviceRegisterer(const string& protocol, const service::Type type) {
+
+ serviceFactory::getInstance()->registerService(
+ make_shared <registeredServiceImpl <S> >(protocol, type)
+ );
+ }
+};
+
+
+} // net
+} // vmime
+
+
+#define REGISTER_SERVICE(p_class, p_name, p_type) \
+ vmime::net::serviceRegisterer <vmime::net::p_class> \
+ p_name(#p_name, vmime::net::service::p_type)
+
+
+#endif // VMIME_BUILDING_DOC
+
diff --git a/vmime-master/src/vmime/net/session.cpp b/vmime-master/src/vmime/net/session.cpp
new file mode 100644
index 0000000..d4b13b4
--- /dev/null
+++ b/vmime-master/src/vmime/net/session.cpp
@@ -0,0 +1,188 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#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() {
+
+#if VMIME_HAVE_TLS_SUPPORT
+ m_tlsProps = make_shared <tls::TLSProperties>();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+}
+
+
+session::session(const propertySet& props)
+ : m_props(props) {
+
+#if VMIME_HAVE_TLS_SUPPORT
+ m_tlsProps = make_shared <tls::TLSProperties>();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+}
+
+
+session::~session() {
+
+}
+
+
+// static
+shared_ptr <session> session::create() {
+
+ return shared_ptr <session>(new session());
+}
+
+
+// static
+shared_ptr <session> session::create(const propertySet& props) {
+
+ return shared_ptr <session>(new session(props));
+}
+
+
+shared_ptr <transport> session::getTransport(const shared_ptr <security::authenticator>& auth) {
+
+ return getTransport(m_props["transport.protocol"], auth);
+}
+
+
+shared_ptr <transport> session::getTransport(
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
+
+ if (!sv || sv->getType() != service::TYPE_TRANSPORT) {
+ return null;
+ }
+
+ return dynamicCast <transport>(sv);
+}
+
+
+shared_ptr <transport> session::getTransport(
+ const utility::url& url,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
+
+ if (!sv || sv->getType() != service::TYPE_TRANSPORT) {
+ return null;
+ }
+
+ return dynamicCast <transport>(sv);
+}
+
+
+shared_ptr <store> session::getStore(const shared_ptr <security::authenticator>& auth) {
+
+ return getStore(m_props["store.protocol"], auth);
+}
+
+
+shared_ptr <store> session::getStore(
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
+
+ if (!sv || sv->getType() != service::TYPE_STORE) {
+ return null;
+ }
+
+ return dynamicCast <store>(sv);
+}
+
+
+shared_ptr <store> session::getStore(
+ const utility::url& url,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
+
+ if (!sv || sv->getType() != service::TYPE_STORE) {
+ return null;
+ }
+
+ return dynamicCast <store>(sv);
+}
+
+
+const propertySet& session::getProperties() const {
+
+ return m_props;
+}
+
+
+propertySet& session::getProperties() {
+
+ return m_props;
+}
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void session::setTLSProperties(const shared_ptr <tls::TLSProperties>& tlsProps) {
+
+ m_tlsProps = make_shared <tls::TLSProperties>(*tlsProps);
+}
+
+
+shared_ptr <tls::TLSProperties> session::getTLSProperties() const {
+
+ return m_tlsProps;
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/session.hpp b/vmime-master/src/vmime/net/session.hpp
new file mode 100644
index 0000000..7ccd0be
--- /dev/null
+++ b/vmime-master/src/vmime/net/session.hpp
@@ -0,0 +1,206 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SESSION_HPP_INCLUDED
+#define VMIME_NET_SESSION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/security/authenticator.hpp"
+
+#if VMIME_HAVE_TLS_SUPPORT
+# include "vmime/net/tls/TLSProperties.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+#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 VMIME_EXPORT session : public object, public enable_shared_from_this <session> {
+
+public:
+
+ /** Construct a new session.
+ *
+ * @return pointer to a new session
+ */
+ static shared_ptr <session> create();
+
+ /** Construct a new session given properties.
+ *
+ * @param props session properties
+ * @return pointer to a new session
+ */
+ static shared_ptr <session> create(const propertySet& props);
+
+ ~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, or NULL if no service is registered for this
+ * protocol or is not a transport protocol
+ */
+ shared_ptr <transport> getTransport(
+ const shared_ptr <security::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, or NULL if no service is registered for this
+ * protocol or is not a transport protocol
+ */
+ shared_ptr <transport> getTransport(
+ const string& protocol,
+ const shared_ptr <security::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, or NULL if no service is registered for this
+ * protocol or is not a transport protocol
+ */
+ shared_ptr <transport> getTransport(
+ const utility::url& url,
+ const shared_ptr <security::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, or NULL if no service is registered for this
+ * protocol or is not a store protocol
+ */
+ shared_ptr <store> getStore(
+ const shared_ptr <security::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, or NULL if no service is registered for this
+ * protocol or is not a store protocol
+ */
+ shared_ptr <store> getStore(
+ const string& protocol,
+ const shared_ptr <security::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, or NULL if no service is registered for this
+ * protocol or is not a store protocol
+ */
+ shared_ptr <store> getStore(
+ const utility::url& url,
+ const shared_ptr <security::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();
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ /** Set properties for SSL/TLS secured connections in this session.
+ *
+ * @param tlsProps SSL/TLS properties
+ */
+ void setTLSProperties(const shared_ptr <tls::TLSProperties>& tlsProps);
+
+ /** Get properties for SSL/TLS secured connections in this session.
+ *
+ * @return SSL/TLS properties
+ */
+ shared_ptr <tls::TLSProperties> getTLSProperties() const;
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+private:
+
+ session();
+ session(const propertySet& props);
+
+
+ propertySet m_props;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ shared_ptr <tls::TLSProperties> m_tlsProps;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SESSION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp
new file mode 100644
index 0000000..3b242d1
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp
@@ -0,0 +1,180 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp"
+
+#include "vmime/net/smtp/SMTPConnection.hpp"
+#include "vmime/net/smtp/SMTPTransport.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPChunkingOutputStreamAdapter::SMTPChunkingOutputStreamAdapter(
+ const shared_ptr <SMTPConnection>& conn,
+ const size_t size,
+ utility::progressListener* progress
+)
+ : m_connection(conn),
+ m_bufferSize(0),
+ m_chunkCount(0),
+ m_totalSize(size),
+ m_totalSent(0),
+ m_progress(progress) {
+
+ if (progress) {
+ progress->start(size);
+ }
+}
+
+
+void SMTPChunkingOutputStreamAdapter::sendChunk(
+ const byte_t* const data,
+ const size_t count,
+ const bool last
+) {
+
+ if (count == 0 && !last) {
+ // Nothing to send
+ return;
+ }
+
+ // Send this chunk
+ m_connection->sendRequest(SMTPCommand::BDAT(count, last));
+ m_connection->getSocket()->sendRaw(data, count);
+
+ ++m_chunkCount;
+
+ if (m_progress) {
+
+ m_totalSent += count;
+ m_totalSize = std::max(m_totalSize, m_totalSent);
+
+ m_progress->progress(m_totalSent, m_totalSize);
+ }
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(count);
+ }
+
+ // If PIPELINING is not supported, read one response for this BDAT command
+ if (!m_connection->hasExtension("PIPELINING")) {
+
+ shared_ptr <SMTPResponse> resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250) {
+ m_connection->getTransport()->disconnect();
+ throw exceptions::command_error("BDAT", resp->getText());
+ }
+
+ // If PIPELINING is supported, read one response for each chunk (ie. number
+ // of BDAT commands issued) after the last chunk has been sent
+ } else if (last) {
+
+ bool invalidReply = false;
+ shared_ptr <SMTPResponse> resp;
+
+ for (unsigned int i = 0 ; i < m_chunkCount ; ++i) {
+
+ resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250) {
+ invalidReply = true;
+ }
+ }
+
+ if (invalidReply) {
+ m_connection->getTransport()->disconnect();
+ throw exceptions::command_error("BDAT", resp->getText());
+ }
+ }
+}
+
+
+void SMTPChunkingOutputStreamAdapter::writeImpl(
+ const byte_t* const data,
+ const size_t count
+) {
+
+ const byte_t* curData = data;
+ size_t curCount = count;
+
+ while (curCount != 0) {
+
+ // Fill the buffer
+ const size_t remaining = sizeof(m_buffer) - m_bufferSize;
+ const size_t bytesToCopy = std::min(remaining, curCount);
+
+ std::copy(curData, curData + bytesToCopy, m_buffer + m_bufferSize);
+
+ m_bufferSize += bytesToCopy;
+ curData += bytesToCopy;
+ curCount -= bytesToCopy;
+
+ // If the buffer is full, send this chunk
+ if (m_bufferSize >= sizeof(m_buffer)) {
+
+ sendChunk(m_buffer, m_bufferSize, /* last */ false);
+ m_bufferSize = 0;
+ }
+ }
+}
+
+
+void SMTPChunkingOutputStreamAdapter::flush() {
+
+ sendChunk(m_buffer, m_bufferSize, /* last */ true);
+ m_bufferSize = 0;
+
+ if (m_progress) {
+ m_progress->stop(m_totalSize);
+ }
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(m_bufferSize);
+ }
+}
+
+
+size_t SMTPChunkingOutputStreamAdapter::getBlockSize() {
+
+ return sizeof(m_buffer);
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp
new file mode 100644
index 0000000..4ef466a
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp
@@ -0,0 +1,94 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/utility/outputStream.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+class SMTPConnection;
+
+
+/** An output stream adapter used with ESMTP CHUNKING extension.
+ */
+class VMIME_EXPORT SMTPChunkingOutputStreamAdapter : public utility::outputStream {
+
+public:
+
+ SMTPChunkingOutputStreamAdapter(
+ const shared_ptr <SMTPConnection>& conn,
+ const size_t size,
+ utility::progressListener* progress
+ );
+
+ void flush();
+
+ size_t getBlockSize();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ SMTPChunkingOutputStreamAdapter(const SMTPChunkingOutputStreamAdapter&);
+
+
+ void sendChunk(const byte_t* const data, const size_t count, const bool last);
+
+
+ shared_ptr <SMTPConnection> m_connection;
+
+ byte_t m_buffer[262144]; // 256 KB
+ size_t m_bufferSize;
+
+ unsigned int m_chunkCount;
+
+ size_t m_totalSize;
+ size_t m_totalSent;
+ utility::progressListener* m_progress;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp b/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp
new file mode 100644
index 0000000..5e533d1
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp
@@ -0,0 +1,258 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/mailbox.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPCommand::SMTPCommand(const string& text, const string& traceText)
+ : m_text(text),
+ m_traceText(traceText)
+{
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::EHLO(const string& hostname) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "EHLO " << hostname;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::HELO(const string& hostname) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "HELO " << hostname;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName, const std::string& initialResponse) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName << " " << initialResponse;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::STARTTLS() {
+
+ return createCommand("STARTTLS");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8,
+ const std::string& dsnRet, const std::string& dsnEnvelopId) {
+
+ return MAIL(mbox, utf8, 0, dsnRet, dsnEnvelopId);
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8, const size_t size,
+ const std::string& dsnRet, const std::string& dsnEnvelopId) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "MAIL FROM:<";
+
+ if (utf8) {
+
+ cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8);
+
+ } else {
+
+ vmime::utility::outputStreamAdapter cmd2(cmd);
+ mbox.getEmail().generate(cmd2);
+ }
+
+ cmd << ">";
+
+ if (!dsnRet.empty()) {
+ cmd << " " << dsn::RET << "=" << dsnRet;
+ }
+ if (!dsnEnvelopId.empty()) {
+ cmd << " " << dsn::ENVID << "=<" << dsnEnvelopId << ">";
+ }
+
+ if (utf8) {
+ cmd << " SMTPUTF8";
+ }
+
+ if (size != 0) {
+ cmd << " SIZE=" << size;
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::RCPT(const mailbox& mbox, const bool utf8,
+ const string& dsnNotify) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "RCPT TO:<";
+
+ if (utf8) {
+
+ cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8);
+
+ } else {
+
+ vmime::utility::outputStreamAdapter cmd2(cmd);
+ mbox.getEmail().generate(cmd2);
+ }
+
+ cmd << ">";
+
+ if (!dsnNotify.empty()) {
+ cmd << " " << dsn::NOTIFY << "=" << dsnNotify;
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::RSET() {
+
+ return createCommand("RSET");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::DATA() {
+
+ return createCommand("DATA");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::BDAT(const size_t chunkSize, const bool last) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "BDAT " << chunkSize;
+
+ if (last) {
+ cmd << " LAST";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::NOOP() {
+
+ return createCommand("NOOP");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::QUIT() {
+
+ return createCommand("QUIT");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::createCommand(const string& text, const string& traceText) {
+
+ if (traceText.empty()) {
+ return shared_ptr <SMTPCommand>(new SMTPCommand(text, text));
+ } else {
+ return shared_ptr <SMTPCommand>(new SMTPCommand(text, traceText));
+ }
+}
+
+
+const string SMTPCommand::getText() const {
+
+ return m_text;
+}
+
+
+const string SMTPCommand::getTraceText() const {
+
+ return m_traceText;
+}
+
+
+void SMTPCommand::writeToSocket(const shared_ptr <socket>& sok, shared_ptr <tracer> tr) {
+
+ sok->send(m_text + "\r\n");
+
+ if (tr) {
+ tr->traceSend(m_traceText);
+ }
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp b/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp
new file mode 100644
index 0000000..9a32d1e
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp
@@ -0,0 +1,125 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+
+
+class mailbox;
+
+
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+class tracer;
+
+
+namespace smtp {
+
+
+/** A SMTP command, as sent to server.
+ */
+class VMIME_EXPORT SMTPCommand : public object {
+
+public:
+
+ static shared_ptr <SMTPCommand> HELO(const string& hostname);
+ static shared_ptr <SMTPCommand> EHLO(const string& hostname);
+ static shared_ptr <SMTPCommand> AUTH(const string& mechName);
+ static shared_ptr <SMTPCommand> AUTH(const string& mechName, const std::string& initialResponse);
+ static shared_ptr <SMTPCommand> STARTTLS();
+ static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8,
+ const std::string& dsnRet, const std::string& dsnEnvelopId);
+ static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8, const size_t size,
+ const std::string& dsnRet, const std::string& dsnEnvelopId);
+ static shared_ptr <SMTPCommand> RCPT(const mailbox& mbox, const bool utf8,
+ const std::string& dsnNotify);
+ static shared_ptr <SMTPCommand> RSET();
+ static shared_ptr <SMTPCommand> DATA();
+ static shared_ptr <SMTPCommand> BDAT(const size_t chunkSize, const bool last);
+ static shared_ptr <SMTPCommand> NOOP();
+ static shared_ptr <SMTPCommand> QUIT();
+
+ /** Creates a new SMTP command with the specified text.
+ *
+ * @param text command text
+ * @return a new SMTPCommand object
+ */
+ static shared_ptr <SMTPCommand> createCommand(const string& text, const string& traceText = "");
+
+ /** Sends this command to the specified socket.
+ *
+ * @param sok socket to which the command will be written
+ * @param tr tracer
+ */
+ virtual void writeToSocket(const shared_ptr <socket>& sok, shared_ptr <tracer> tr);
+
+ /** Returns the full text of the command, including command name
+ * and parameters (if any).
+ *
+ * @return command text (eg. "RCPT TO:<vincent@kisli.com>")
+ */
+ virtual const string getText() const;
+
+ /** Returns the full text of the command, suitable for outputing
+ * to the tracer.
+ *
+ * @return trace text (eg. "LOGIN myusername ***")
+ */
+ virtual const string getTraceText() const;
+
+protected:
+
+ SMTPCommand(const string& text, const string& traceText);
+ SMTPCommand(const SMTPCommand&);
+
+private:
+
+ string m_text;
+ string m_traceText;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp
new file mode 100644
index 0000000..eab7086
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp
@@ -0,0 +1,160 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPCommandSet.hpp"
+
+#include "vmime/net/socket.hpp"
+
+#include "vmime/mailbox.hpp"
+
+#include <stdexcept>
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPCommandSet::SMTPCommandSet(const bool pipeline)
+ : SMTPCommand("", ""),
+ m_pipeline(pipeline),
+ m_started(false),
+ m_lastCommandSent() {
+
+}
+
+
+// static
+shared_ptr <SMTPCommandSet> SMTPCommandSet::create(const bool pipeline) {
+
+ return shared_ptr <SMTPCommandSet>(new SMTPCommandSet(pipeline));
+}
+
+
+void SMTPCommandSet::addCommand(const shared_ptr <SMTPCommand>& cmd) {
+
+ if (m_started) {
+ throw std::runtime_error("Could not add command to pipeline: "
+ "one or more commands have already been sent to the server.");
+ }
+
+ m_commands.push_back(cmd);
+}
+
+
+void SMTPCommandSet::writeToSocket(const shared_ptr <socket>& sok, const shared_ptr <tracer>& tr) {
+
+ if (m_pipeline) {
+
+ if (!m_started) {
+
+ // Send all commands at once
+ for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ;
+ it != m_commands.end() ; ++it) {
+
+ shared_ptr <SMTPCommand> cmd = *it;
+ cmd->writeToSocket(sok, tr);
+ }
+ }
+
+ if (!m_commands.empty()) {
+
+ // Advance the pointer to last command sent
+ shared_ptr <SMTPCommand> cmd = m_commands.front();
+ m_commands.pop_front();
+
+ m_lastCommandSent = cmd;
+ }
+
+ } else {
+
+ if (!m_commands.empty()) {
+
+ // Send only one command
+ shared_ptr <SMTPCommand> cmd = m_commands.front();
+ m_commands.pop_front();
+
+ cmd->writeToSocket(sok, tr);
+
+ m_lastCommandSent = cmd;
+ }
+ }
+
+ m_started = true;
+}
+
+
+const string SMTPCommandSet::getText() const {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ;
+ it != m_commands.end() ; ++it) {
+
+ cmd << (*it)->getText() << "\r\n";
+ }
+
+ return cmd.str();
+}
+
+
+const string SMTPCommandSet::getTraceText() const {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ;
+ it != m_commands.end() ; ++it) {
+
+ cmd << (*it)->getTraceText() << "\r\n";
+ }
+
+ return cmd.str();
+}
+
+
+bool SMTPCommandSet::isFinished() const {
+
+ return (m_pipeline && m_started) || (m_commands.size() == 0 && m_started);
+}
+
+
+shared_ptr <SMTPCommand> SMTPCommandSet::getLastCommandSent() const {
+
+ return m_lastCommandSent;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp
new file mode 100644
index 0000000..2fd977c
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp
@@ -0,0 +1,106 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include <list>
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** A set of SMTP commands, which may be sent all at once
+ * to the server if pipelining is supported.
+ */
+class VMIME_EXPORT SMTPCommandSet : public SMTPCommand {
+
+public:
+
+ /** Creates a new set of SMTP commands.
+ *
+ * @param pipeline set to true if the server supports pipelining
+ * @return a new SMTPCommandSet object
+ */
+ static shared_ptr <SMTPCommandSet> create(const bool pipeline);
+
+ /** Adds a new command to this set.
+ * If one or more comments have already been sent to the server,
+ * an exception will be thrown.
+ *
+ * @param cmd command to add
+ */
+ void addCommand(const shared_ptr <SMTPCommand>& cmd);
+
+ /** Tests whether all commands have been sent.
+ *
+ * @return true if all commands have been sent,
+ * or false otherwise
+ */
+ bool isFinished() const;
+
+ /** Returns the last command which has been sent.
+ *
+ * @return a pointer to a SMTPCommand, of NULL if no command
+ * has been sent yet
+ */
+ shared_ptr <SMTPCommand> getLastCommandSent() const;
+
+
+ void writeToSocket(const shared_ptr <socket>& sok, const shared_ptr <tracer>& tr);
+
+ const string getText() const;
+ const string getTraceText() const;
+
+private:
+
+ SMTPCommandSet(const bool pipeline);
+ SMTPCommandSet(const SMTPCommandSet&);
+
+
+ bool m_pipeline;
+ bool m_started;
+ std::list <shared_ptr <SMTPCommand> > m_commands;
+ shared_ptr <SMTPCommand> m_lastCommandSent;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp b/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp
new file mode 100644
index 0000000..07d0376
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp
@@ -0,0 +1,714 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPConnection.hpp"
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/SASLContext.hpp"
+#else
+ #include "vmime/utility/encoder/b64Encoder.hpp"
+ #include "vmime/utility/inputStreamStringAdapter.hpp"
+ #include "vmime/utility/outputStreamStringAdapter.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/tls/TLSSession.hpp"
+ #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (m_transport.lock()->getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const SMTPServiceInfos&>(m_transport.lock()->getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (m_transport.lock()->getInfos().hasProperty(getSession(), \
+ dynamic_cast <const SMTPServiceInfos&>(m_transport.lock()->getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+
+SMTPConnection::SMTPConnection(
+ const shared_ptr <SMTPTransport>& transport,
+ const shared_ptr <security::authenticator>& auth
+)
+ : m_transport(transport),
+ m_auth(auth),
+ m_socket(null),
+ m_timeoutHandler(null),
+ m_authenticated(false),
+ m_secured(false),
+ m_extendedSMTP(false) {
+
+ static int connectionId = 0;
+
+ if (transport->getTracerFactory()) {
+ m_tracer = transport->getTracerFactory()->create(transport, ++connectionId);
+ }
+}
+
+
+SMTPConnection::~SMTPConnection() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ } else if (m_socket) {
+ internalDisconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void SMTPConnection::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);
+
+ shared_ptr <SMTPTransport> transport = m_transport.lock();
+
+ // Create the time-out handler
+ if (transport->getTimeoutHandlerFactory()) {
+ m_timeoutHandler = transport->getTimeoutHandlerFactory()->create();
+ }
+
+ // Create and connect the socket
+ m_socket = transport->getSocketFactory()->create(m_timeoutHandler);
+ m_socket->setTracer(m_tracer);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (transport->isSMTPS()) { // dedicated port/SMTPS
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ transport->getCertificateVerifier(),
+ transport->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
+
+ } else
+#endif // VMIME_HAVE_TLS_SUPPORT
+ {
+ m_cntInfos = make_shared <defaultConnectionInfos>(address, port);
+ }
+
+ m_socket->connect(address, port);
+
+ // Connection
+ //
+ // eg: C: <connection to server>
+ // --- S: 220 smtp.domain.com Service ready
+
+ shared_ptr <SMTPResponse> resp;
+
+ if ((resp = readResponse())->getCode() != 220) {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(resp->getText());
+ }
+
+ // Identification
+ helo();
+
+#if VMIME_HAVE_TLS_SUPPORT
+ // Setup secured connection, if requested
+ const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);
+ const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);
+
+ if (!transport->isSMTPS() && tls) { // only if not SMTPS
+
+ try {
+
+ startTLS();
+
+ // Non-fatal error
+ } catch (exceptions::command_error&) {
+
+ if (tlsRequired) {
+ throw;
+ } else {
+ // TLS is not required, so don't bother
+ }
+
+ // Fatal error
+ } catch (...) {
+
+ throw;
+ }
+
+ // Must reissue a EHLO command [RFC-2487, 5.2]
+ helo();
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // Authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH)) {
+ authenticate();
+ } else {
+ m_authenticated = true;
+ }
+}
+
+
+void SMTPConnection::helo() {
+
+ // First, try Extended SMTP (ESMTP)
+ //
+ // eg: C: EHLO thismachine.ourdomain.com
+ // S: 250-smtp.theserver.com
+ // S: 250-AUTH CRAM-MD5 DIGEST-MD5
+ // S: 250-PIPELINING
+ // S: 250 SIZE 2555555555
+
+ sendRequest(SMTPCommand::EHLO(platform::getHandler()->getHostName()));
+
+ shared_ptr <SMTPResponse> resp;
+
+ if ((resp = readResponse())->getCode() != 250) {
+
+ // Next, try "Basic" SMTP
+ //
+ // eg: C: HELO thismachine.ourdomain.com
+ // S: 250 OK
+
+ sendRequest(SMTPCommand::HELO(platform::getHandler()->getHostName()));
+
+ if ((resp = readResponse())->getCode() != 250) {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(resp->getLastLine().getText());
+ }
+
+ m_extendedSMTP = false;
+ m_extensions.clear();
+
+ } else {
+
+ m_extendedSMTP = true;
+ m_extensions.clear();
+
+ // Get supported extensions from SMTP response
+ // One extension per line, format is: EXT PARAM1 PARAM2...
+ for (size_t i = 1, n = resp->getLineCount() ; i < n ; ++i) {
+
+ const string line = resp->getLineAt(i).getText();
+
+ std::istringstream iss(line);
+ iss.imbue(std::locale::classic());
+
+ string ext;
+ iss >> ext;
+
+ std::vector <string> params;
+ string param;
+
+ // Special case: some servers send "AUTH=MECH [MECH MECH...]"
+ if (ext.length() >= 5 && utility::stringUtils::toUpper(ext.substr(0, 5)) == "AUTH=") {
+
+ params.push_back(utility::stringUtils::toUpper(ext.substr(5)));
+ ext = "AUTH";
+ }
+
+ while (iss >> param) {
+ params.push_back(utility::stringUtils::toUpper(param));
+ }
+
+ m_extensions[ext] = params;
+ }
+ }
+}
+
+
+bool SMTPConnection::hasExtension(
+ const std::string& extName,
+ std::vector <string>* params
+) const {
+
+ std::map <string, std::vector <string> >::const_iterator
+ it = m_extensions.find(extName);
+
+ if (it != m_extensions.end()) {
+
+ if (params) {
+ *params = (*it).second;
+ }
+
+ return true;
+
+ } else {
+
+ return false;
+ }
+}
+
+
+void SMTPConnection::authenticate() {
+
+ if (!m_extendedSMTP) {
+ internalDisconnect();
+ throw exceptions::command_error("AUTH", "ESMTP not supported.");
+ }
+
+ getAuthenticator()->setService(m_transport.lock());
+
+#if VMIME_HAVE_SASL_SUPPORT
+ // Try SASL authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) {
+
+ try {
+
+ authenticateSASL();
+
+ m_authenticated = true;
+ return;
+
+ } catch (exception&) {
+
+ internalDisconnect();
+ throw;
+ }
+ }
+#else // no SASL
+
+ // allow AUTH PLAIN over TLS - it is a popular and simple mechanism
+ if (m_secured) {
+
+ std::vector <string> authMechs;
+ hasExtension("AUTH", &authMechs);
+
+ if (authMechs.empty()) {
+ throw exceptions::authentication_error("No AUTH mechanism available.");
+ }
+
+ const string plain("PLAIN");
+
+ if (std::find(authMechs.begin(), authMechs.end(), plain) != authMechs.end()) {
+
+ const string username = getAuthenticator()->getUsername();
+ const string password = getAuthenticator()->getPassword();
+ const string authToken = username + '\0' + username + '\0' + password;
+
+ utility::inputStreamStringAdapter in(authToken);
+ string authTokenBase64;
+ utility::outputStreamStringAdapter out(authTokenBase64);
+
+ vmime::utility::encoder::b64Encoder encoder;
+ encoder.encode(in, out);
+
+ sendRequest(SMTPCommand::AUTH(plain, authTokenBase64));
+
+ shared_ptr <SMTPResponse> response = readResponse();
+
+ const int code = response ? response->getCode() : -1;
+
+ if (code == 235) {
+ m_authenticated = true;
+ return;
+ }
+ }
+ }
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // No other authentication method is possible
+ throw exceptions::authentication_error("All authentication methods failed");
+}
+
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+void SMTPConnection::authenticateSASL() {
+
+ if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) {
+ throw exceptions::authentication_error("No SASL authenticator available.");
+ }
+
+ // Obtain SASL mechanisms supported by server from ESMTP extensions
+ std::vector <string> saslMechs;
+ hasExtension("AUTH", &saslMechs);
+
+ if (saslMechs.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList;
+
+ shared_ptr <security::sasl::SASLContext> saslContext =
+ security::sasl::SASLContext::create();
+
+ for (unsigned int i = 0 ; i < saslMechs.size() ; ++i) {
+
+ try {
+
+ mechList.push_back
+ (saslContext->createMechanism(saslMechs[i]));
+
+ } catch (exceptions::no_such_mechanism&) {
+
+ // Ignore mechanism
+ }
+ }
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try to suggest a mechanism among all those supported
+ shared_ptr <security::sasl::SASLMechanism> suggestedMech =
+ saslContext->suggestMechanism(mechList);
+
+ if (!suggestedMech) {
+ throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
+ }
+
+ // Allow application to choose which mechanisms to use
+ mechList = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())->
+ getAcceptableMechanisms(mechList, suggestedMech);
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try each mechanism in the list in turn
+ for (unsigned int i = 0 ; i < mechList.size() ; ++i) {
+
+ shared_ptr <security::sasl::SASLMechanism> mech = mechList[i];
+
+ shared_ptr <security::sasl::SASLSession> saslSession =
+ saslContext->createSession("smtp", getAuthenticator(), mech);
+
+ saslSession->init();
+
+ if (saslSession->getMechanism()->hasInitialResponse()) {
+
+ byte_t* initialResp = 0;
+ size_t initialRespLen = 0;
+
+ saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
+
+ string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
+ delete [] initialResp;
+
+ if (encodedInitialResp.empty()) {
+ sendRequest(SMTPCommand::AUTH(mech->getName(), "="));
+ } else {
+ sendRequest(SMTPCommand::AUTH(mech->getName(), encodedInitialResp));
+ }
+
+ } else {
+
+ sendRequest(SMTPCommand::AUTH(mech->getName()));
+ }
+
+ for (bool cont = true ; cont ; ) {
+
+ shared_ptr <SMTPResponse> response = readResponse();
+
+ switch (response->getCode()) {
+
+ case 235: {
+
+ m_socket = saslSession->getSecuredSocket(m_socket);
+ return;
+ }
+ case 334: {
+
+ byte_t* challenge = 0;
+ size_t challengeLen = 0;
+
+ byte_t* resp = 0;
+ size_t respLen = 0;
+
+ try {
+
+ // Extract challenge
+ saslContext->decodeB64(response->getText(), &challenge, &challengeLen);
+
+ // Prepare response
+ saslSession->evaluateChallenge(challenge, challengeLen, &resp, &respLen);
+
+ // Send response
+ const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n";
+ m_socket->sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length());
+
+ if (m_tracer) {
+ m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange");
+ }
+
+ } catch (exceptions::sasl_exception& e) {
+
+ if (challenge) {
+ delete [] challenge;
+ challenge = NULL;
+ }
+
+ if (resp) {
+ delete [] resp;
+ resp = NULL;
+ }
+
+ // Cancel SASL exchange
+ m_socket->send("*\r\n");
+
+ if (m_tracer) {
+ m_tracer->traceSend("*");
+ }
+
+ } catch (...) {
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ throw;
+ }
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ break;
+ }
+ default:
+
+ cont = false;
+ break;
+ }
+ }
+ }
+
+ throw exceptions::authentication_error("Could not authenticate using SASL: all mechanisms failed.");
+}
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void SMTPConnection::startTLS() {
+
+ try {
+
+ sendRequest(SMTPCommand::STARTTLS());
+
+ shared_ptr <SMTPResponse> resp = readResponse();
+
+ if (resp->getCode() != 220) {
+
+ throw SMTPCommandError(
+ "STARTTLS", resp->getText(), resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ getTransport()->getCertificateVerifier(),
+ getTransport()->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ tlsSocket->handshake();
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(
+ m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket
+ );
+
+ } catch (exceptions::command_error&) {
+
+ // Non-fatal error
+ throw;
+
+ } catch (exception&) {
+
+ // Fatal error
+ internalDisconnect();
+ throw;
+ }
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+void SMTPConnection::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ internalDisconnect();
+}
+
+
+void SMTPConnection::internalDisconnect() {
+
+ if (isConnected()) {
+
+ try {
+
+ sendRequest(SMTPCommand::QUIT());
+
+ // Do not wait for server response. This is contrary to the RFC, but
+ // some servers never send a response to a QUIT command.
+
+ } catch (exception&) {
+
+ // Not important
+ }
+ }
+
+ m_socket->disconnect();
+ m_socket = null;
+
+ m_timeoutHandler = null;
+
+ m_authenticated = false;
+ m_extendedSMTP = false;
+
+ m_secured = false;
+ m_cntInfos = null;
+}
+
+
+void SMTPConnection::sendRequest(const shared_ptr <SMTPCommand>& cmd) {
+
+ cmd->writeToSocket(m_socket, m_tracer);
+}
+
+
+shared_ptr <SMTPResponse> SMTPConnection::readResponse() {
+
+ shared_ptr <SMTPResponse> resp = SMTPResponse::readResponse(
+ m_tracer, m_socket, m_timeoutHandler, m_responseState
+ );
+
+ m_responseState = resp->getCurrentState();
+
+ return resp;
+}
+
+
+bool SMTPConnection::isConnected() const {
+
+ return m_socket && m_socket->isConnected() && m_authenticated;
+}
+
+
+bool SMTPConnection::isSecuredConnection() const {
+
+ return m_secured;
+}
+
+
+shared_ptr <connectionInfos> SMTPConnection::getConnectionInfos() const {
+
+ return m_cntInfos;
+}
+
+
+shared_ptr <SMTPTransport> SMTPConnection::getTransport() {
+
+ return m_transport.lock();
+}
+
+
+shared_ptr <session> SMTPConnection::getSession() {
+
+ return m_transport.lock()->getSession();
+}
+
+
+shared_ptr <socket> SMTPConnection::getSocket() {
+
+ return m_socket;
+}
+
+
+shared_ptr <tracer> SMTPConnection::getTracer() {
+
+ return m_tracer;
+}
+
+
+shared_ptr <timeoutHandler> SMTPConnection::getTimeoutHandler() {
+
+ return m_timeoutHandler;
+}
+
+
+shared_ptr <security::authenticator> SMTPConnection::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp b/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp
new file mode 100644
index 0000000..d8a2375
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp
@@ -0,0 +1,136 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/messageId.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/session.hpp"
+#include "vmime/net/connectionInfos.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+
+
+namespace smtp {
+
+
+class SMTPTransport;
+
+
+/** Manage connection to a SMTP server.
+ */
+class VMIME_EXPORT SMTPConnection : public object {
+
+public:
+
+ SMTPConnection(
+ const shared_ptr <SMTPTransport>& transport,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~SMTPConnection();
+
+
+ virtual void connect();
+ virtual bool isConnected() const;
+ virtual void disconnect();
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ virtual shared_ptr <SMTPTransport> getTransport();
+ virtual shared_ptr <socket> getSocket();
+ virtual shared_ptr <timeoutHandler> getTimeoutHandler();
+ virtual shared_ptr <security::authenticator> getAuthenticator();
+ virtual shared_ptr <session> getSession();
+ virtual shared_ptr <tracer> getTracer();
+
+ void sendRequest(const shared_ptr <SMTPCommand>& cmd);
+ shared_ptr <SMTPResponse> readResponse();
+
+ bool hasExtension(const std::string& extName, std::vector <string>* params = NULL) const;
+
+private:
+
+ void internalDisconnect();
+
+ void helo();
+ void authenticate();
+#if VMIME_HAVE_SASL_SUPPORT
+ void authenticateSASL();
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ void startTLS();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+ weak_ptr <SMTPTransport> m_transport;
+
+ shared_ptr <security::authenticator> m_auth;
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ SMTPResponse::state m_responseState;
+
+ bool m_authenticated;
+ bool m_secured;
+
+ shared_ptr <connectionInfos> m_cntInfos;
+
+ bool m_extendedSMTP;
+ std::map <string, std::vector <string> > m_extensions;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp b/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp
new file mode 100644
index 0000000..e3b4652
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp
@@ -0,0 +1,212 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+//
+// SMTPCommandError
+//
+
+SMTPCommandError::SMTPCommandError(
+ const string& command,
+ const string& response,
+ const string& desc,
+ const int statusCode,
+ const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other
+)
+ : command_error(command, response, desc, other),
+ m_status(statusCode),
+ m_exStatus(extendedStatusCode) {
+
+}
+
+
+SMTPCommandError::SMTPCommandError(
+ const string& command,
+ const string& response,
+ const int statusCode,
+ const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other
+)
+ : command_error(command, response, "", other),
+ m_status(statusCode),
+ m_exStatus(extendedStatusCode) {
+
+}
+
+
+SMTPCommandError::~SMTPCommandError() throw() {
+
+}
+
+
+int SMTPCommandError::statusCode() const {
+
+ return m_status;
+}
+
+
+const SMTPResponse::enhancedStatusCode SMTPCommandError::extendedStatusCode() const {
+
+ return m_exStatus;
+}
+
+
+exception* SMTPCommandError::clone() const {
+
+ return new SMTPCommandError(*this);
+}
+
+
+const char* SMTPCommandError::name() const throw() {
+
+ return "SMTPCommandError";
+}
+
+
+//
+// SMTPMessageSizeExceedsMaxLimitsException
+//
+
+SMTPMessageSizeExceedsMaxLimitsException::SMTPMessageSizeExceedsMaxLimitsException(const exception& other)
+ : net_exception("Message size exceeds maximum server limits (permanent error).", other) {
+
+}
+
+
+SMTPMessageSizeExceedsMaxLimitsException::~SMTPMessageSizeExceedsMaxLimitsException() throw() {
+
+}
+
+
+exception* SMTPMessageSizeExceedsMaxLimitsException::clone() const {
+
+ return new SMTPMessageSizeExceedsMaxLimitsException(*this);
+}
+
+
+const char* SMTPMessageSizeExceedsMaxLimitsException::name() const throw() {
+
+ return "SMTPMessageSizeExceedsMaxLimitsException";
+}
+
+
+//
+// SMTPMessageSizeExceedsCurLimitsException
+//
+
+SMTPMessageSizeExceedsCurLimitsException::SMTPMessageSizeExceedsCurLimitsException(const exception& other)
+ : net_exception("Message size exceeds current server limits (temporary storage error).", other) {
+
+}
+
+
+SMTPMessageSizeExceedsCurLimitsException::~SMTPMessageSizeExceedsCurLimitsException() throw() {
+
+}
+
+
+exception* SMTPMessageSizeExceedsCurLimitsException::clone() const {
+
+ return new SMTPMessageSizeExceedsCurLimitsException(*this);
+}
+
+
+const char* SMTPMessageSizeExceedsCurLimitsException::name() const throw() {
+
+ return "SMTPMessageSizeExceedsCurLimitsException";
+}
+
+
+//
+// SMTPExtensionNotSupportedException
+//
+
+SMTPExtensionNotSupportedException::SMTPExtensionNotSupportedException(const string &what, const exception& other)
+ : net_exception(what.empty() ? "A required extension is not supported by the SMTP server." : what, other) {
+
+}
+
+
+SMTPExtensionNotSupportedException::~SMTPExtensionNotSupportedException() throw() {
+
+}
+
+
+exception* SMTPExtensionNotSupportedException::clone() const {
+
+ return new SMTPExtensionNotSupportedException(*this);
+}
+
+
+const char* SMTPExtensionNotSupportedException::name() const throw() {
+
+ return "SMTPExtensionNotSupportedException";
+}
+
+
+//
+// SMTPDSNExtensionNotSupportedException
+//
+
+SMTPDSNExtensionNotSupportedException::SMTPDSNExtensionNotSupportedException(const exception& other)
+ : SMTPExtensionNotSupportedException("RFC-1891 DSN extension is not supported by the SMTP server.", other) {
+
+}
+
+
+SMTPDSNExtensionNotSupportedException::~SMTPDSNExtensionNotSupportedException() throw() {
+
+}
+
+
+exception* SMTPDSNExtensionNotSupportedException::clone() const {
+ return new SMTPDSNExtensionNotSupportedException(*this);
+}
+
+
+const char* SMTPDSNExtensionNotSupportedException::name() const throw() {
+
+ return "SMTPDSNExtensionNotSupportedException";
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp b/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp
new file mode 100644
index 0000000..488ee2e
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp
@@ -0,0 +1,159 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/exception.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** SMTP Command error: a SMTP command failed.
+ */
+class VMIME_EXPORT SMTPCommandError : public exceptions::command_error {
+
+public:
+
+ SMTPCommandError(
+ const string& command,
+ const string& response,
+ const string& desc,
+ const int statusCode,
+ const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other = NO_EXCEPTION
+ );
+
+ SMTPCommandError(
+ const string& command,
+ const string& response,
+ const int statusCode, const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other = NO_EXCEPTION
+ );
+
+ ~SMTPCommandError() throw();
+
+ /** Returns the SMTP status code for this error.
+ *
+ * @return status code (protocol-dependent)
+ */
+ int statusCode() const;
+
+ /** Returns the extended status code (following RFC-3463) for this
+ * error, if available.
+ *
+ * @return status code
+ */
+ const SMTPResponse::enhancedStatusCode extendedStatusCode() const;
+
+
+ exception* clone() const;
+ const char* name() const throw();
+
+private:
+
+ int m_status;
+ SMTPResponse::enhancedStatusCode m_exStatus;
+};
+
+
+/** SMTP error: message size exceeds maximum server limits.
+ * This is a permanent error.
+ */
+class VMIME_EXPORT SMTPMessageSizeExceedsMaxLimitsException : public exceptions::net_exception {
+
+public:
+
+ SMTPMessageSizeExceedsMaxLimitsException(const exception& other = NO_EXCEPTION);
+ ~SMTPMessageSizeExceedsMaxLimitsException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** SMTP error: message size exceeds current server limits.
+ * This is a temporary error (you may retry later).
+ */
+class VMIME_EXPORT SMTPMessageSizeExceedsCurLimitsException : public exceptions::net_exception {
+
+public:
+
+ SMTPMessageSizeExceedsCurLimitsException(const exception& other = NO_EXCEPTION);
+ ~SMTPMessageSizeExceedsCurLimitsException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** SMTP error: a required extension is not supported by the server.
+ */
+class VMIME_EXPORT SMTPExtensionNotSupportedException : public exceptions::net_exception {
+
+public:
+
+ SMTPExtensionNotSupportedException(const string& what, const exception& other = NO_EXCEPTION);
+ ~SMTPExtensionNotSupportedException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** SMTP error: RFC-1891 DSN extension is not supported by the server.
+ */
+class VMIME_EXPORT SMTPDSNExtensionNotSupportedException : public SMTPExtensionNotSupportedException {
+
+public:
+
+ SMTPDSNExtensionNotSupportedException(const exception& other = NO_EXCEPTION);
+ ~SMTPDSNExtensionNotSupportedException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp b/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp
new file mode 100644
index 0000000..2234705
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp
@@ -0,0 +1,366 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+#include "vmime/platform.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include <cctype>
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPResponse::SMTPResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+)
+ : m_socket(sok),
+ m_timeoutHandler(toh),
+ m_tracer(tr),
+ m_responseBuffer(st.responseBuffer),
+ m_responseContinues(false) {
+
+}
+
+
+SMTPResponse::SMTPResponse(const SMTPResponse&)
+ : vmime::object() {
+
+ // Not used
+}
+
+
+int SMTPResponse::getCode() const {
+
+ const int firstCode = m_lines[0].getCode();
+
+ for (unsigned int i = 1 ; i < m_lines.size() ; ++i) {
+
+ // All response codes returned must be equal
+ // or else this in an error...
+ if (m_lines[i].getCode() != firstCode) {
+ return 0;
+ }
+ }
+
+ return firstCode;
+}
+
+
+const SMTPResponse::enhancedStatusCode SMTPResponse::getEnhancedCode() const {
+
+ return m_lines[m_lines.size() - 1].getEnhancedCode();
+}
+
+
+const string SMTPResponse::getText() const {
+
+ string text = m_lines[0].getText();
+
+ for (unsigned int i = 1 ; i < m_lines.size() ; ++i) {
+
+ text += '\n';
+ text += m_lines[i].getText();
+ }
+
+ return text;
+}
+
+
+// static
+shared_ptr <SMTPResponse> SMTPResponse::readResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+) {
+
+ shared_ptr <SMTPResponse> resp =
+ shared_ptr <SMTPResponse>(new SMTPResponse(tr, sok, toh, st));
+
+ resp->readResponse();
+
+ return resp;
+}
+
+
+void SMTPResponse::readResponse() {
+
+ responseLine line = getNextResponse();
+ m_lines.push_back(line);
+
+ while (m_responseContinues) {
+ line = getNextResponse();
+ m_lines.push_back(line);
+ }
+}
+
+
+const string SMTPResponse::readResponseLine() {
+
+ string currentBuffer = m_responseBuffer;
+
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ while (true) {
+
+ // Get a line from the response buffer
+ const size_t lineEnd = currentBuffer.find_first_of('\n');
+
+ if (lineEnd != string::npos) {
+
+ size_t actualLineEnd = lineEnd;
+
+ if (actualLineEnd != 0 && currentBuffer[actualLineEnd - 1] == '\r') { // CRLF case
+ actualLineEnd--;
+ }
+
+ const string line(currentBuffer.begin(), currentBuffer.begin() + actualLineEnd);
+
+ currentBuffer.erase(currentBuffer.begin(), currentBuffer.begin() + lineEnd + 1);
+ m_responseBuffer = currentBuffer;
+
+ if (m_tracer) {
+ m_tracer->traceReceive(line);
+ }
+
+ return line;
+ }
+
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Receive data from the socket
+ string receiveBuffer;
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+ m_socket->waitForRead();
+ continue;
+ }
+
+ currentBuffer += receiveBuffer;
+ }
+}
+
+
+const SMTPResponse::responseLine SMTPResponse::getNextResponse() {
+
+ string line = readResponseLine();
+
+ const int code = extractResponseCode(line);
+ string text;
+
+ m_responseContinues = (line.length() >= 4 && line[3] == '-');
+
+ if (line.length() > 4) {
+ text = utility::stringUtils::trim(line.substr(4));
+ } else {
+ text = "";
+ }
+
+ return responseLine(code, text, extractEnhancedCode(text));
+}
+
+
+// static
+int SMTPResponse::extractResponseCode(const string& response) {
+
+ int code = 0;
+
+ if (response.length() >= 3) {
+
+ code = (response[0] - '0') * 100
+ + (response[1] - '0') * 10
+ + (response[2] - '0');
+ }
+
+ return code;
+}
+
+
+// static
+const SMTPResponse::enhancedStatusCode SMTPResponse::extractEnhancedCode(const string& responseText) {
+
+ enhancedStatusCode enhCode;
+
+ std::istringstream iss(responseText);
+ iss.imbue(std::locale::classic());
+
+ if (std::isdigit(iss.peek())) {
+
+ iss >> enhCode.klass;
+
+ if (iss.get() == '.' && std::isdigit(iss.peek())) {
+
+ iss >> enhCode.subject;
+
+ if (iss.get() == '.' && std::isdigit(iss.peek())) {
+
+ iss >> enhCode.detail;
+ return enhCode;
+ }
+ }
+ }
+
+ return enhancedStatusCode(); // no enhanced code found
+}
+
+
+const SMTPResponse::responseLine SMTPResponse::getLineAt(const size_t pos) const {
+
+ return m_lines[pos];
+}
+
+
+size_t SMTPResponse::getLineCount() const {
+
+ return m_lines.size();
+}
+
+
+const SMTPResponse::responseLine SMTPResponse::getLastLine() const {
+
+ return m_lines[m_lines.size() - 1];
+}
+
+
+const SMTPResponse::state SMTPResponse::getCurrentState() const {
+
+ state st;
+ st.responseBuffer = m_responseBuffer;
+
+ return st;
+}
+
+
+
+// SMTPResponse::responseLine
+
+SMTPResponse::responseLine::responseLine(
+ const int code,
+ const string& text,
+ const enhancedStatusCode& enhCode
+)
+ : m_code(code),
+ m_text(text),
+ m_enhCode(enhCode) {
+
+}
+
+
+void SMTPResponse::responseLine::setCode(const int code) {
+
+ m_code = code;
+}
+
+
+int SMTPResponse::responseLine::getCode() const {
+
+ return m_code;
+}
+
+
+void SMTPResponse::responseLine::setEnhancedCode(const enhancedStatusCode& enhCode) {
+
+ m_enhCode = enhCode;
+}
+
+
+const SMTPResponse::enhancedStatusCode SMTPResponse::responseLine::getEnhancedCode() const {
+
+ return m_enhCode;
+}
+
+
+void SMTPResponse::responseLine::setText(const string& text) {
+
+ m_text = text;
+}
+
+
+const string SMTPResponse::responseLine::getText() const {
+
+ return m_text;
+}
+
+
+
+// SMTPResponse::enhancedStatusCode
+
+
+SMTPResponse::enhancedStatusCode::enhancedStatusCode()
+ : klass(0),
+ subject(0),
+ detail(0) {
+
+}
+
+
+SMTPResponse::enhancedStatusCode::enhancedStatusCode(const enhancedStatusCode& enhCode)
+ : klass(enhCode.klass),
+ subject(enhCode.subject),
+ detail(enhCode.detail) {
+
+}
+
+
+std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code) {
+
+ os << code.klass << '.' << code.subject << '.' << code.detail;
+ return os;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp b/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp
new file mode 100644
index 0000000..2eec7f4
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp
@@ -0,0 +1,200 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+class tracer;
+
+
+namespace smtp {
+
+
+/** A SMTP response, as sent by the server.
+ */
+class VMIME_EXPORT SMTPResponse : public object {
+
+public:
+
+ /** Current state of response parser. */
+ struct state {
+
+ string responseBuffer;
+ };
+
+ /** Enhanced status code (as per RFC-3463). */
+ struct enhancedStatusCode {
+
+ enhancedStatusCode();
+ enhancedStatusCode(const enhancedStatusCode& enhCode);
+
+ unsigned short klass; /**< Success/failure. */
+ unsigned short subject; /**< Source of anomaly. */
+ unsigned short detail; /**< Precise error condition. */
+ };
+
+ /** An element of a SMTP response. */
+ class responseLine {
+
+ public:
+
+ responseLine(const int code, const string& text, const enhancedStatusCode& enhCode);
+
+ void setCode(const int code);
+ int getCode() const;
+
+ void setEnhancedCode(const enhancedStatusCode& enhCode);
+ const enhancedStatusCode getEnhancedCode() const;
+
+ void setText(const string& text);
+ const string getText() const;
+
+ private:
+
+ int m_code;
+ string m_text;
+ enhancedStatusCode m_enhCode;
+ };
+
+ /** Receive and parse a new SMTP response from the
+ * specified socket.
+ *
+ * @param tr tracer
+ * @param sok socket from which to read
+ * @param toh time-out handler
+ * @param st previous state of response parser for the specified socket
+ * @return SMTP response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <SMTPResponse> readResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+ );
+
+ /** Return the SMTP response code.
+ *
+ * @return response code
+ */
+ int getCode() const;
+
+ /** Return the SMTP enhanced status code, if available.
+ *
+ * @return enhanced status code
+ */
+ const enhancedStatusCode getEnhancedCode() const;
+
+ /** Return the SMTP response text.
+ * The text of each line is concatenated.
+ *
+ * @return response text
+ */
+ const string getText() const;
+
+ /** Return the response line at the specified position.
+ *
+ * @param pos line index
+ * @return line at the specified index
+ */
+ const responseLine getLineAt(const size_t pos) const;
+
+ /** Return the number of lines in the response.
+ *
+ * @return number of lines in the response
+ */
+ size_t getLineCount() const;
+
+ /** Return the last line in the response.
+ *
+ * @return last response line
+ */
+ const responseLine getLastLine() const;
+
+ /** Returns the current state of the response parser.
+ *
+ * @return current parser state
+ */
+ const state getCurrentState() const;
+
+private:
+
+ SMTPResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+ );
+
+ SMTPResponse(const SMTPResponse&);
+
+ void readResponse();
+
+ const string readResponseLine();
+ const responseLine getNextResponse();
+
+ static int extractResponseCode(const string& response);
+ static const enhancedStatusCode extractEnhancedCode(const string& responseText);
+
+
+ std::vector <responseLine> m_lines;
+
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ string m_responseBuffer;
+ bool m_responseContinues;
+};
+
+
+VMIME_EXPORT std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code);
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp b/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp
new file mode 100644
index 0000000..5158aa9
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPSTransport.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPSTransport::SMTPSTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : SMTPTransport(sess, auth, true) {
+
+}
+
+
+SMTPSTransport::~SMTPSTransport() {
+
+}
+
+
+const string SMTPSTransport::getProtocolName() const {
+
+ return "smtps";
+}
+
+
+
+// Service infos
+
+SMTPServiceInfos SMTPSTransport::sm_infos(true);
+
+
+const serviceInfos& SMTPSTransport::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& SMTPSTransport::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp b/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp
new file mode 100644
index 0000000..f19b3c5
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** SMTPS transport service.
+ */
+class VMIME_EXPORT SMTPSTransport : public SMTPTransport {
+
+public:
+
+ SMTPSTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~SMTPSTransport();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+private:
+
+ static SMTPServiceInfos sm_infos;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp
new file mode 100644
index 0000000..a2ee3d5
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPServiceInfos::SMTPServiceInfos(const bool smtps)
+ : m_smtps(smtps) {
+
+}
+
+
+const string SMTPServiceInfos::getPropertyPrefix() const {
+
+ if (m_smtps) {
+ return "transport.smtps.";
+ } else {
+ return "transport.smtp.";
+ }
+}
+
+
+const SMTPServiceInfos::props& SMTPServiceInfos::getProperties() const {
+
+ static props smtpProps = {
+ // SMTP-specific options
+ property("options.need-authentication", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ property("options.pipelining", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.chunking", serviceInfos::property::TYPE_BOOLEAN, "true"),
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "25"),
+ };
+
+ static props smtpsProps = {
+ // SMTP-specific options
+ property("options.need-authentication", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ property("options.pipelining", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.chunking", serviceInfos::property::TYPE_BOOLEAN, "true"),
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "465"),
+ };
+
+ return m_smtps ? smtpsProps : smtpProps;
+}
+
+
+const std::vector <serviceInfos::property> SMTPServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ // SMTP-specific options
+ list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH);
+#if VMIME_HAVE_SASL_SUPPORT
+ list.push_back(p.PROPERTY_OPTIONS_SASL);
+ list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ list.push_back(p.PROPERTY_AUTH_USERNAME);
+ list.push_back(p.PROPERTY_AUTH_PASSWORD);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (!m_smtps) {
+ list.push_back(p.PROPERTY_CONNECTION_TLS);
+ list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED);
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ list.push_back(p.PROPERTY_SERVER_ADDRESS);
+ list.push_back(p.PROPERTY_SERVER_PORT);
+
+ return list;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp
new file mode 100644
index 0000000..005a0a2
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp
@@ -0,0 +1,93 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** Information about SMTP service.
+ */
+class VMIME_EXPORT SMTPServiceInfos : public serviceInfos {
+
+public:
+
+ SMTPServiceInfos(const bool smtps);
+
+ struct props {
+ // SMTP-specific options
+ serviceInfos::property PROPERTY_OPTIONS_NEEDAUTH;
+#if VMIME_HAVE_SASL_SUPPORT
+ serviceInfos::property PROPERTY_OPTIONS_SASL;
+ serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ serviceInfos::property PROPERTY_OPTIONS_PIPELINING;
+ serviceInfos::property PROPERTY_OPTIONS_CHUNKING;
+
+ // Common properties
+ serviceInfos::property PROPERTY_AUTH_USERNAME;
+ serviceInfos::property PROPERTY_AUTH_PASSWORD;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ serviceInfos::property PROPERTY_CONNECTION_TLS;
+ serviceInfos::property PROPERTY_CONNECTION_TLS_REQUIRED;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ serviceInfos::property PROPERTY_SERVER_ADDRESS;
+ serviceInfos::property PROPERTY_SERVER_PORT;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+
+private:
+
+ const bool m_smtps;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp b/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp
new file mode 100644
index 0000000..561bd59
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp
@@ -0,0 +1,502 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPResponse.hpp"
+#include "vmime/net/smtp/SMTPCommand.hpp"
+#include "vmime/net/smtp/SMTPCommandSet.hpp"
+#include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/mailboxList.hpp"
+#include "vmime/message.hpp"
+
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/outputStreamSocketAdapter.hpp"
+#include "vmime/utility/streamUtils.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPTransport::SMTPTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured
+)
+ : transport(sess, getInfosInstance(), auth),
+ m_isSMTPS(secured),
+ m_needReset(false) {
+
+}
+
+
+SMTPTransport::~SMTPTransport() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string SMTPTransport::getProtocolName() const {
+
+ return "smtp";
+}
+
+
+bool SMTPTransport::isSMTPS() const {
+
+ return m_isSMTPS;
+}
+
+
+void SMTPTransport::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ m_connection = make_shared <SMTPConnection>(
+ dynamicCast <SMTPTransport>(shared_from_this()), getAuthenticator()
+ );
+
+ m_connection->connect();
+}
+
+
+bool SMTPTransport::isConnected() const {
+
+ return m_connection && m_connection->isConnected();
+}
+
+
+bool SMTPTransport::isSecuredConnection() const {
+
+ if (!m_connection) {
+ return false;
+ }
+
+ return m_connection->isSecuredConnection();
+}
+
+
+shared_ptr <connectionInfos> SMTPTransport::getConnectionInfos() const {
+
+ if (!m_connection) {
+ return null;
+ }
+
+ return m_connection->getConnectionInfos();
+}
+
+
+shared_ptr <SMTPConnection> SMTPTransport::getConnection() {
+
+ return m_connection;
+}
+
+
+void SMTPTransport::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ m_connection->disconnect();
+ m_connection = null;
+}
+
+
+void SMTPTransport::noop() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ m_connection->sendRequest(SMTPCommand::NOOP());
+
+ shared_ptr <SMTPResponse> resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250) {
+ throw SMTPCommandError("NOOP", resp->getText(), resp->getCode(), resp->getEnhancedCode());
+ }
+}
+
+
+// static
+bool SMTPTransport::mailboxNeedsUTF8(const mailbox& mb) {
+
+ bool all7bit =
+ utility::stringUtils::is7bit(mb.getEmail().getLocalName().getBuffer())
+ && utility::stringUtils::is7bit(mb.getEmail().getDomainName().getBuffer());
+
+ for (size_t i = 0, n = mb.getName().getWordCount() ; all7bit && i != n ; ++i) {
+ all7bit = utility::stringUtils::is7bit(mb.getName().getWordAt(i)->getBuffer());
+ }
+
+ return !all7bit;
+}
+
+
+void SMTPTransport::sendEnvelope(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ const mailbox& sender,
+ bool sendDATACommand,
+ const size_t size,
+ const dsnAttributes& dsnAttrs
+) {
+
+ // If no recipient/expeditor was found, throw an exception
+ if (recipients.isEmpty()) {
+ throw exceptions::no_recipient();
+ } else if (expeditor.isEmpty()) {
+ throw exceptions::no_expeditor();
+ }
+
+ // If DSN extension is used, ensure it is supported by the server
+ if (!dsnAttrs.isEmpty() && !m_connection->hasExtension("DSN")) {
+ throw SMTPDSNExtensionNotSupportedException();
+ }
+
+
+ const bool needReset = m_needReset;
+ const bool hasPipelining = m_connection->hasExtension("PIPELINING") &&
+ getInfos().getPropertyValue <bool>(getSession(),
+ dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().PROPERTY_OPTIONS_PIPELINING);
+
+ shared_ptr <SMTPResponse> resp;
+ shared_ptr <SMTPCommandSet> commands = SMTPCommandSet::create(hasPipelining);
+
+ // Emit a "RSET" command if we previously sent a message on this connection
+ if (needReset) {
+ commands->addCommand(SMTPCommand::RSET());
+ }
+
+ // Check whether we need SMTPUTF8
+ const bool hasSMTPUTF8 = m_connection->hasExtension("SMTPUTF8");
+ bool needSMTPUTF8 = false;
+
+ if (!sender.isEmpty()) {
+ needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(sender);
+ } else {
+ needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(expeditor);
+ }
+
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+
+ const mailbox& mbox = *recipients.getMailboxAt(i);
+ needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(mbox);
+ }
+
+ // Emit the "MAIL" command
+ const bool hasSize = m_connection->hasExtension("SIZE");
+
+ if (!sender.isEmpty()) {
+
+ commands->addCommand(
+ SMTPCommand::MAIL(
+ sender, hasSMTPUTF8 && needSMTPUTF8, hasSize ? size : 0,
+ dsnAttrs.getNotificationConditions(),
+ dsnAttrs.getEnvelopId()
+ )
+ );
+
+ } else {
+
+ commands->addCommand(
+ SMTPCommand::MAIL(
+ expeditor, hasSMTPUTF8 && needSMTPUTF8, hasSize ? size : 0,
+ dsnAttrs.getNotificationConditions(),
+ dsnAttrs.getEnvelopId()
+ )
+ );
+ }
+
+ // Now, we will need to reset next time
+ m_needReset = true;
+
+ // Emit a "RCPT TO" command for each recipient
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+
+ const mailbox& mbox = *recipients.getMailboxAt(i);
+ commands->addCommand(SMTPCommand::RCPT(mbox, hasSMTPUTF8 && needSMTPUTF8,
+ dsnAttrs.getNotificationConditions()));
+ }
+
+ // Prepare sending of message data
+ if (sendDATACommand) {
+ commands->addCommand(SMTPCommand::DATA());
+ }
+
+ // Read response for "RSET" command
+ if (needReset) {
+
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250 &&
+ resp->getCode() != 200) { // RFC-876: << In reply to a RSET and/or a NOOP command,
+ // some servers reply "200" >>
+
+ disconnect();
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+
+ // Read response for "MAIL" command
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ if ((resp = m_connection->readResponse())->getCode() != 250) {
+
+ // SIZE extension: insufficient system storage
+ if (resp->getCode() == 452) {
+
+ throw SMTPMessageSizeExceedsCurLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // SIZE extension: message size exceeds fixed maximum message size
+ } else if (resp->getCode() == 552) {
+
+ throw SMTPMessageSizeExceedsMaxLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // Other error
+ } else {
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+
+ // Read responses for "RCPT TO" commands
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250 &&
+ resp->getCode() != 251) {
+
+ // SIZE extension: insufficient system storage
+ if (resp->getCode() == 452) {
+
+ throw SMTPMessageSizeExceedsCurLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // SIZE extension: message size exceeds fixed maximum message size
+ } else if (resp->getCode() == 552) {
+
+ throw SMTPMessageSizeExceedsMaxLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // Other error
+ } else {
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+ }
+
+ // Read response for "DATA" command
+ if (sendDATACommand) {
+
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ if ((resp = m_connection->readResponse())->getCode() != 354) {
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+}
+
+
+void SMTPTransport::send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& dsnAttrs
+) {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ // Send message envelope
+ sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ true, size,
+ dsnAttrs);
+
+ // Send the message data
+ // Stream copy with "\n." to "\n.." transformation
+ utility::outputStreamSocketAdapter sos(*m_connection->getSocket());
+ utility::dotFilteredOutputStream fos(sos);
+
+ utility::bufferedStreamCopy(is, fos, size, progress);
+
+ fos.flush();
+
+ // Send end-of-data delimiter
+ m_connection->getSocket()->send("\r\n.\r\n");
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(size);
+ m_connection->getTracer()->traceSend(".");
+ }
+
+ shared_ptr <SMTPResponse> resp;
+
+ if ((resp = m_connection->readResponse())->getCode() != 250) {
+ throw SMTPCommandError("DATA", resp->getText(), resp->getCode(), resp->getEnhancedCode());
+ }
+}
+
+
+void SMTPTransport::send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& dsnAttrs
+) {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ // Generate the message with Internationalized Email support,
+ // if this is supported by the SMTP server
+ generationContext ctx(generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(m_connection->hasExtension("SMTPUTF8"));
+
+ // If CHUNKING is not supported, generate the message to a temporary
+ // buffer then use the send() method which takes an inputStream
+ if (!m_connection->hasExtension("CHUNKING") ||
+ !getInfos().getPropertyValue <bool>(getSession(),
+ dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().PROPERTY_OPTIONS_CHUNKING)) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ctx, ossAdapter);
+
+ const string& str(oss.str());
+
+ utility::inputStreamStringAdapter isAdapter(str);
+
+ send(expeditor, recipients, isAdapter, str.length(), progress, sender, dsnAttrs);
+ return;
+ }
+
+ // Send message envelope
+ const size_t msgSize = msg->getGeneratedSize(ctx);
+
+ sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ false, msgSize, dsnAttrs);
+
+ // Send the message by chunks
+ SMTPChunkingOutputStreamAdapter chunkStream(m_connection, msgSize, progress);
+
+ msg->generate(ctx, chunkStream);
+
+ chunkStream.flush();
+}
+
+
+
+// Service infos
+
+SMTPServiceInfos SMTPTransport::sm_infos(false);
+
+
+const serviceInfos& SMTPTransport::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& SMTPTransport::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp b/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp
new file mode 100644
index 0000000..cd7c712
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/transport.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/net/smtp/SMTPServiceInfos.hpp"
+#include "vmime/net/smtp/SMTPConnection.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+class SMTPCommand;
+
+
+/** SMTP transport service.
+ */
+class VMIME_EXPORT SMTPTransport : public transport {
+
+public:
+
+ SMTPTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured = false
+ );
+
+ ~SMTPTransport();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ void send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ void send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+ shared_ptr <SMTPConnection> getConnection();
+
+ bool isSMTPS() const;
+
+private:
+
+ static bool mailboxNeedsUTF8(const mailbox& mb);
+
+ /** Send the MAIL and RCPT commands to the server, checking the
+ * response, and using pipelining if supported by the server.
+ * Optionally, the DATA command can also be sent.
+ *
+ * @param expeditor expeditor mailbox
+ * @param recipients list of recipient mailboxes
+ * @param sender envelope sender (if empty, expeditor will be used)
+ * @param sendDATACommand if true, the DATA command will be sent
+ * @param size message size, in bytes (or 0, if not known)
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ void sendEnvelope(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ const mailbox& sender,
+ bool sendDATACommand,
+ const size_t size,
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+
+ shared_ptr <SMTPConnection> m_connection;
+
+
+ const bool m_isSMTPS;
+
+ bool m_needReset;
+
+ // Service infos
+ static SMTPServiceInfos sm_infos;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/smtp.hpp b/vmime-master/src/vmime/net/smtp/smtp.hpp
new file mode 100644
index 0000000..4c0b17d
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/smtp.hpp
@@ -0,0 +1,33 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTP_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTP_HPP_INCLUDED
+
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPSTransport.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+
+#endif // VMIME_NET_SMTP_SMTP_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/socket.hpp b/vmime-master/src/vmime/net/socket.hpp
new file mode 100644
index 0000000..a236a9f
--- /dev/null
+++ b/vmime-master/src/vmime/net/socket.hpp
@@ -0,0 +1,223 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SOCKET_HPP_INCLUDED
+#define VMIME_NET_SOCKET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/base.hpp"
+
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Interface for connecting to servers.
+ */
+class VMIME_EXPORT socket : public object {
+
+public:
+
+ enum Status {
+ STATUS_WOULDBLOCK = 0xf, /**< The operation would block. Retry later. */
+ STATUS_WANT_READ = 0x1, /**< The socket wants to read data, retry when data is available. */
+ STATUS_WANT_WRITE = 0x2 /**< The socket wants to write data, retry when data can be written. */
+ };
+
+
+ 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 bool isConnected() const = 0;
+
+ /** Block until new data is available for reading. The function will
+ * timeout after msecs milliseconds.
+ *
+ * @param timeout maximum wait time, in milliseconds (default is 30000);
+ * resolution is 10ms
+ * @return true if data is available, or false if the operation timed out
+ */
+ virtual bool waitForRead(const int msecs = 30000) = 0;
+
+ /** Block until pending data has been written and new data can be written.
+ * The function will timeout after msecs milliseconds.
+ *
+ * @param timeout maximum wait time, in milliseconds (default is 30000);
+ * resolution is 10ms
+ * @return true if new data can be written immediately, or false if the
+ * operation timed out
+ */
+ virtual bool waitForWrite(const int msecs = 30000) = 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 size_t receiveRaw(byte_t* buffer, const size_t count) = 0;
+
+ /** Send text data to the socket.
+ *
+ * @param buffer data to send
+ */
+ virtual void send(const string& buffer) = 0;
+
+ /** Send text data to the socket.
+ *
+ * @param str null-terminated string
+ */
+ virtual void send(const char* str) = 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 byte_t* buffer, const size_t count) = 0;
+
+ /** Send raw data to the socket.
+ * Function may returns before all data is sent.
+ *
+ * @param buffer data to send
+ * @param count number of bytes to send (size of buffer)
+ * @return number of bytes sent
+ */
+ virtual size_t sendRawNonBlocking(const byte_t* buffer, const size_t count) = 0;
+
+ /** Return the preferred maximum block size when reading
+ * from or writing to this stream.
+ *
+ * @return block size, in bytes
+ */
+ virtual size_t getBlockSize() const = 0;
+
+ /** Return the current status of this socket.
+ *
+ * @return status flags for this socket
+ */
+ virtual unsigned int getStatus() const = 0;
+
+ /** Return the hostname of peer this socket is connected to.
+ *
+ * @return name of the peer, or numeric address if it cannot be found
+ */
+ virtual const string getPeerName() const = 0;
+
+ /** Return the address of peer this socket is connected to.
+ *
+ * @return numeric address of the peer
+ */
+ virtual const string getPeerAddress() const = 0;
+
+ /** Return the timeout handler associated with this socket.
+ *
+ * @return timeout handler, or NULL if none is set
+ */
+ virtual shared_ptr <timeoutHandler> getTimeoutHandler() = 0;
+
+ /** Set the tracer used by this socket. Tracer will only be used
+ * to report socket-specific events such as connection (not when
+ * sending/receiving data).
+ *
+ * @param tracer tracer to use
+ */
+ virtual void setTracer(const shared_ptr <tracer>& tracer) = 0;
+
+ /** Return the tracer used by this socket.
+ *
+ * @return tracer, or NULL if none is set
+ */
+ virtual shared_ptr <tracer> getTracer() = 0;
+
+protected:
+
+ socket() { }
+
+private:
+
+ socket(const socket&) : object() { }
+};
+
+
+/** A class to create 'socket' objects.
+ */
+class socketFactory : public object {
+
+public:
+
+ virtual ~socketFactory() { }
+
+ /** Creates a socket without timeout handler.
+ *
+ * @return a new socket
+ */
+ virtual shared_ptr <socket> create() = 0;
+
+ /** Creates a socket with the specified timeout handler.
+ *
+ * @param th timeout handler
+ * @return a new socket
+ */
+ virtual shared_ptr <socket> create(const shared_ptr <timeoutHandler>& th) = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SOCKET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/store.cpp b/vmime-master/src/vmime/net/store.cpp
new file mode 100644
index 0000000..3c9a66d
--- /dev/null
+++ b/vmime-master/src/vmime/net/store.cpp
@@ -0,0 +1,57 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/store.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+store::store(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+)
+ : service(sess, infos, auth) {
+
+}
+
+
+store::Type store::getType() const {
+
+ return TYPE_STORE;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/store.hpp b/vmime-master/src/vmime/net/store.hpp
new file mode 100644
index 0000000..a96f267
--- /dev/null
+++ b/vmime-master/src/vmime/net/store.hpp
@@ -0,0 +1,115 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_STORE_HPP_INCLUDED
+#define VMIME_NET_STORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#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 VMIME_EXPORT store : public service {
+
+protected:
+
+ store(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+public:
+
+ /** Return the default folder. This is protocol dependent
+ * and usually is the INBOX folder.
+ *
+ * @return default folder
+ */
+ virtual shared_ptr <folder> getDefaultFolder() = 0;
+
+ /** Return the root folder. This is protocol dependent
+ * and usually is the user's mail drop root folder.
+ *
+ * @return root folder
+ */
+ virtual shared_ptr <folder> getRootFolder() = 0;
+
+ /** Return the folder specified by the path.
+ *
+ * @param path absolute folder path
+ * @return folder at the specified path
+ */
+ virtual shared_ptr <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 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 int getCapabilities() const = 0;
+
+
+ Type getType() const;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_STORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/timeoutHandler.hpp b/vmime-master/src/vmime/net/timeoutHandler.hpp
new file mode 100644
index 0000000..fed1bc4
--- /dev/null
+++ b/vmime-master/src/vmime/net/timeoutHandler.hpp
@@ -0,0 +1,89 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
+#define VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** A class to manage timeouts in messaging services. This can be used
+ * to stop operations that takes too much time to complete (ie. no data
+ * received from the server for a long time if the network link is down).
+ */
+class VMIME_EXPORT timeoutHandler : public object {
+
+public:
+
+ virtual ~timeoutHandler() { }
+
+ /** Called to test if the time limit has been reached.
+ *
+ * @return true if the timeout delay is elapsed
+ */
+ virtual bool isTimeOut() = 0;
+
+ /** Called to reset the timeout counter.
+ */
+ virtual void resetTimeOut() = 0;
+
+ /** Called when the time limit has been reached (when
+ * isTimeOut() returned true).
+ *
+ * @return true to continue (and reset the timeout)
+ * or false to cancel the current operation
+ */
+ virtual bool handleTimeOut() = 0;
+};
+
+
+/** A class to create 'timeoutHandler' objects.
+ */
+class timeoutHandlerFactory : public object {
+
+public:
+
+ virtual ~timeoutHandlerFactory() { }
+
+ virtual shared_ptr <timeoutHandler> create() = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/TLSProperties.cpp b/vmime-master/src/vmime/net/tls/TLSProperties.cpp
new file mode 100644
index 0000000..f7721d4
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSProperties.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
diff --git a/vmime-master/src/vmime/net/tls/TLSProperties.hpp b/vmime-master/src/vmime/net/tls/TLSProperties.hpp
new file mode 100644
index 0000000..94341ca
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSProperties.hpp
@@ -0,0 +1,105 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+/** Holds options for a TLS session.
+ */
+class VMIME_EXPORT TLSProperties : public object {
+
+public:
+
+ TLSProperties();
+ TLSProperties(const TLSProperties&);
+
+
+ /** Predefined generic cipher suites (work with all TLS libraries). */
+ enum GenericCipherSuite {
+
+ CIPHERSUITE_HIGH, /**< High encryption cipher suites (> 128 bits). */
+ CIPHERSUITE_MEDIUM, /**< Medium encryption cipher suites (>= 128 bits). */
+ CIPHERSUITE_LOW, /**< Low encryption cipher suites (>= 64 bits). */
+
+ CIPHERSUITE_DEFAULT /**< Default cipher suite. */
+ };
+
+ /** Sets the cipher suite preferences for a SSL/TLS session, using
+ * predefined, generic suites. This works with all underlying TLS
+ * libraries (OpenSSL and GNU TLS).
+ *
+ * @param cipherSuite predefined cipher suite
+ */
+ void setCipherSuite(const GenericCipherSuite cipherSuite);
+
+ /** Sets the cipher suite preferences for a SSL/TLS session, using
+ * a character string. The format and meaning of the string depend
+ * on the underlying TLS library.
+ *
+ * For GNU TLS, read this:
+ * http://gnutls.org/manual/html_node/Priority-Strings.html
+ *
+ * For OpenSSL, read this:
+ * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
+ *
+ * @param cipherSuite cipher suite as a string
+ */
+ void setCipherSuite(const string& cipherSuite);
+
+ /** Returns the cipher suite preferences for a SSL/TLS session, as
+ * a character string. The format and meaning of the string depend
+ * on the underlying TLS library (see setCipherSuite() method).
+ *
+ * @return cipher suite string
+ */
+ const string getCipherSuite() const;
+
+private:
+
+ shared_ptr <object> m_data;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp
new file mode 100644
index 0000000..055dfea
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#include "vmime/net/tls/TLSSession.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSSecuredConnectionInfos::TLSSecuredConnectionInfos(
+ const string& host,
+ const port_t port,
+ const shared_ptr <TLSSession>& tlsSession,
+ const shared_ptr <TLSSocket>& tlsSocket
+)
+ : m_host(host),
+ m_port(port),
+ m_tlsSession(tlsSession),
+ m_tlsSocket(tlsSocket) {
+
+}
+
+
+const string TLSSecuredConnectionInfos::getHost() const {
+
+ return m_host;
+}
+
+
+port_t TLSSecuredConnectionInfos::getPort() const {
+
+ return m_port;
+}
+
+
+shared_ptr <const security::cert::certificateChain> TLSSecuredConnectionInfos::getPeerCertificates() const {
+
+ return m_tlsSocket->getPeerCertificates();
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
diff --git a/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp
new file mode 100644
index 0000000..c65e9d2
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/securedConnectionInfos.hpp"
+
+#include "vmime/security/cert/certificateChain.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSocket;
+
+
+/** Information about a TLS-secured connection used by a service.
+ */
+class VMIME_EXPORT TLSSecuredConnectionInfos : public securedConnectionInfos {
+
+public:
+
+ TLSSecuredConnectionInfos(
+ const string& host,
+ const port_t port,
+ const shared_ptr <TLSSession>& tlsSession,
+ const shared_ptr <TLSSocket>& tlsSocket
+ );
+
+ const string getHost() const;
+ port_t getPort() const;
+
+ /** Return the peer's certificate (chain) as sent by the peer.
+ *
+ * @return server certificate chain
+ */
+ shared_ptr <const security::cert::certificateChain> getPeerCertificates() const;
+
+private:
+
+ string m_host;
+ port_t m_port;
+
+ shared_ptr <TLSSession> m_tlsSession;
+ shared_ptr <TLSSocket> m_tlsSocket;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/TLSSession.cpp b/vmime-master/src/vmime/net/tls/TLSSession.cpp
new file mode 100644
index 0000000..ab8b7c3
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSession.cpp
@@ -0,0 +1,48 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSSession.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSSession::TLSSession() {
+
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/net/tls/TLSSession.hpp b/vmime-master/src/vmime/net/tls/TLSSession.hpp
new file mode 100644
index 0000000..9e84fe7
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSession.hpp
@@ -0,0 +1,96 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSocket.hpp"
+#include "vmime/net/tls/TLSProperties.hpp"
+
+#include "vmime/security/cert/certificateVerifier.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+/** Describe a TLS connection between a client and a server.
+ */
+class VMIME_EXPORT TLSSession : public object, public enable_shared_from_this <TLSSession> {
+
+public:
+
+ /** Create and initialize a new TLS session.
+ *
+ * @param cv object responsible for verifying certificates
+ * sent by the server
+ * @param props TLS properties for this session
+ * @return a new TLS session
+ */
+ static shared_ptr <TLSSession> create(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+ );
+
+ /** Create a new socket that adds a TLS security layer around
+ * an existing socket. You should create only one socket
+ * per session.
+ *
+ * @param sok socket to wrap
+ * @return TLS socket wrapper
+ */
+ virtual shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok) = 0;
+
+ /** Get the object responsible for verifying certificates when
+ * using secured connections (TLS/SSL).
+ */
+ virtual shared_ptr <security::cert::certificateVerifier> getCertificateVerifier() = 0;
+
+protected:
+
+ TLSSession();
+
+private:
+
+ TLSSession(const TLSSession&);
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/TLSSocket.cpp b/vmime-master/src/vmime/net/tls/TLSSocket.cpp
new file mode 100644
index 0000000..fbca082
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSocket.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
diff --git a/vmime-master/src/vmime/net/tls/TLSSocket.hpp b/vmime-master/src/vmime/net/tls/TLSSocket.hpp
new file mode 100644
index 0000000..ca50aa8
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSocket.hpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/exception.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/security/cert/certificateChain.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+
+
+/** Add a TLS security layer to an existing socket.
+ */
+class VMIME_EXPORT TLSSocket : public socket {
+
+public:
+
+ /** Create a new socket object that adds a security layer
+ * around an existing socket.
+ *
+ * @param session TLS session
+ * @param sok socket to wrap
+ */
+ static shared_ptr <TLSSocket> wrap(const shared_ptr <TLSSession>& session, const shared_ptr <socket>& sok);
+
+ /** Starts a TLS handshake on this connection.
+ *
+ * @throw exceptions::tls_exception if a fatal error occurs
+ * during the negociation process, exceptions::operation_timed_out
+ * if a time-out occurs
+ */
+ virtual void handshake() = 0;
+
+ /** Return the peer's certificate (chain) as sent by the peer.
+ *
+ * @return server certificate chain, or NULL if the handshake
+ * has not been performed yet
+ */
+ virtual shared_ptr <security::cert::certificateChain> getPeerCertificates() = 0;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp
new file mode 100644
index 0000000..b2996fb
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp
@@ -0,0 +1,113 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/base.hpp"
+#include "vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp"
+
+#include <gnutls/gnutls.h>
+#if GNUTLS_VERSION_NUMBER < 0x030000
+#include <gnutls/extra.h>
+#endif
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSProperties::TLSProperties()
+ : m_data(make_shared <TLSProperties_GnuTLS>()) {
+
+ setCipherSuite(CIPHERSUITE_DEFAULT);
+}
+
+
+TLSProperties::TLSProperties(const TLSProperties& props)
+ : object(),
+ m_data(make_shared <TLSProperties_GnuTLS>()) {
+
+ *dynamicCast <TLSProperties_GnuTLS>(m_data) = *dynamicCast <TLSProperties_GnuTLS>(props.m_data);
+}
+
+
+void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) {
+
+ switch (cipherSuite) {
+
+ case CIPHERSUITE_HIGH:
+
+ setCipherSuite("SECURE256:%SSL3_RECORD_VERSION");
+ break;
+
+ case CIPHERSUITE_MEDIUM:
+
+ setCipherSuite("SECURE128:%SSL3_RECORD_VERSION");
+ break;
+
+ case CIPHERSUITE_LOW:
+
+ setCipherSuite("NORMAL:%SSL3_RECORD_VERSION");
+ break;
+
+ default:
+ case CIPHERSUITE_DEFAULT:
+
+ setCipherSuite("NORMAL:%SSL3_RECORD_VERSION");
+ break;
+ }
+}
+
+
+void TLSProperties::setCipherSuite(const string& cipherSuite) {
+
+ dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite = cipherSuite;
+}
+
+
+const string TLSProperties::getCipherSuite() const {
+
+ return dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite;
+}
+
+
+
+TLSProperties_GnuTLS& TLSProperties_GnuTLS::operator=(const TLSProperties_GnuTLS& other) {
+
+ cipherSuite = other.cipherSuite;
+
+ return *this;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp
new file mode 100644
index 0000000..96bbaea
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSProperties_GnuTLS : public object {
+
+public:
+
+ TLSProperties_GnuTLS& operator=(const TLSProperties_GnuTLS& other);
+
+
+ string cipherSuite;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp
new file mode 100644
index 0000000..8586537
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp
@@ -0,0 +1,313 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#if GNUTLS_VERSION_NUMBER < 0x030000
+#include <gnutls/extra.h>
+#endif
+
+
+// Dependency on gcrypt is not needed since GNU TLS version 2.12.
+// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651
+#if GNUTLS_VERSION_NUMBER <= 0x020b00
+# define VMIME_GNUTLS_NEEDS_GCRYPT 1
+#endif
+
+#if VMIME_HAVE_PTHREAD
+# include <pthread.h>
+# if VMIME_GNUTLS_NEEDS_GCRYPT
+# include <gcrypt.h>
+# endif
+# include <errno.h>
+#endif // VMIME_HAVE_PTHREAD
+
+#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp"
+
+#include "vmime/exception.hpp"
+
+
+// Enable GnuTLS debugging by defining GNUTLS_DEBUG
+//#define GNUTLS_DEBUG 1
+
+
+#include <sstream>
+#include <iomanip>
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+ #include <iostream>
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+
+#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
+extern "C"
+{
+ GCRY_THREAD_OPTION_PTHREAD_IMPL;
+}
+#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+// Initialize GNU TLS library
+struct TLSGlobal {
+
+ TLSGlobal() {
+
+#if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
+ #if VMIME_GNUTLS_NEEDS_GCRYPT
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+ #endif // VMIME_GNUTLS_NEEDS_GCRYPT
+#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
+
+ gnutls_global_init();
+ //gnutls_global_init_extra();
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+ gnutls_global_set_log_function(TLSLogFunc);
+ gnutls_global_set_log_level(10);
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+ gnutls_anon_allocate_client_credentials(&anonCred);
+ gnutls_certificate_allocate_credentials(&certCred);
+ }
+
+ ~TLSGlobal() {
+
+ gnutls_anon_free_client_credentials(anonCred);
+ gnutls_certificate_free_credentials(certCred);
+
+ gnutls_global_deinit();
+ }
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+
+ static void TLSLogFunc(int level, const char *str) {
+
+ std::cerr << "GNUTLS: [" << level << "] " << str << std::endl;
+ }
+
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+
+ gnutls_anon_client_credentials_t anonCred;
+ gnutls_certificate_credentials_t certCred;
+};
+
+static TLSGlobal g_gnutlsGlobal;
+
+
+#endif // VMIME_BUILDING_DOC
+
+
+
+// static
+shared_ptr <TLSSession> TLSSession::create(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+) {
+
+ return make_shared <TLSSession_GnuTLS>(cv, props);
+}
+
+
+TLSSession_GnuTLS::TLSSession_GnuTLS(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+)
+ : m_certVerifier(cv),
+ m_props(props) {
+
+ int res;
+
+ m_gnutlsSession = new gnutls_session_t;
+
+ if (gnutls_init(m_gnutlsSession, GNUTLS_CLIENT) != 0) {
+ throw std::bad_alloc();
+ }
+
+ // Sets some default priority on the ciphers, key exchange methods,
+ // macs and compression methods.
+#ifdef VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
+ gnutls_dh_set_prime_bits(*m_gnutlsSession, 128);
+
+ if ((res = gnutls_priority_set_direct
+ (*m_gnutlsSession, m_props->getCipherSuite().c_str(), NULL)) != 0) {
+
+ throwTLSException("gnutls_priority_set_direct", res);
+ }
+
+#else // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
+
+ gnutls_set_default_priority(*m_gnutlsSession);
+
+ // Sets the priority on the certificate types supported by gnutls.
+ // Priority is higher for types specified before others. After
+ // specifying the types you want, you must append a 0.
+ const int certTypePriority[] = { GNUTLS_CRT_X509, 0 };
+
+ res = gnutls_certificate_type_set_priority(*m_gnutlsSession, certTypePriority);
+
+ if (res < 0) {
+ throwTLSException("gnutls_certificate_type_set_priority", res);
+ }
+
+ // Sets the priority on the protocol types
+ const int protoPriority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
+
+ res = gnutls_protocol_set_priority(*m_gnutlsSession, protoPriority);
+
+ if (res < 0) {
+ throwTLSException("gnutls_certificate_type_set_priority", res);
+ }
+
+ // Priority on the ciphers
+ const int cipherPriority[] = {
+ GNUTLS_CIPHER_ARCFOUR_128,
+ GNUTLS_CIPHER_3DES_CBC,
+ GNUTLS_CIPHER_AES_128_CBC,
+ GNUTLS_CIPHER_AES_256_CBC,
+ GNUTLS_CIPHER_ARCFOUR_40,
+ GNUTLS_CIPHER_RC2_40_CBC,
+ GNUTLS_CIPHER_DES_CBC,
+ 0
+ };
+
+ gnutls_cipher_set_priority(*m_gnutlsSession, cipherPriority);
+
+ // Priority on MACs
+ const int macPriority[] = {
+ GNUTLS_MAC_SHA,
+ GNUTLS_MAC_MD5,
+ 0
+ };
+
+ gnutls_mac_set_priority(*m_gnutlsSession, macPriority);
+
+ // Priority on key exchange methods
+ const int kxPriority[] = {
+ GNUTLS_KX_RSA,
+ GNUTLS_KX_DHE_DSS,
+ GNUTLS_KX_DHE_RSA,
+ GNUTLS_KX_ANON_DH,
+ GNUTLS_KX_SRP,
+ GNUTLS_KX_RSA_EXPORT,
+ GNUTLS_KX_SRP_RSA,
+ GNUTLS_KX_SRP_DSS,
+ 0
+ };
+
+ gnutls_kx_set_priority(*m_gnutlsSession, kxPriority);
+
+ // Priority on compression methods
+ const int compressionPriority[] = {
+ GNUTLS_COMP_ZLIB,
+ //GNUTLS_COMP_LZO,
+ GNUTLS_COMP_NULL,
+ 0
+ };
+
+ gnutls_compression_set_priority(*m_gnutlsSession, compressionPriority);
+
+#endif // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
+
+ // Initialize credentials
+ gnutls_credentials_set(
+ *m_gnutlsSession, GNUTLS_CRD_ANON, g_gnutlsGlobal.anonCred
+ );
+
+ gnutls_credentials_set(
+ *m_gnutlsSession, GNUTLS_CRD_CERTIFICATE, g_gnutlsGlobal.certCred
+ );
+}
+
+
+TLSSession_GnuTLS::TLSSession_GnuTLS(const TLSSession_GnuTLS&)
+ : TLSSession() {
+
+ // Not used
+}
+
+
+TLSSession_GnuTLS::~TLSSession_GnuTLS() {
+
+ try {
+
+ if (m_gnutlsSession) {
+
+ gnutls_deinit(*m_gnutlsSession);
+
+ delete m_gnutlsSession;
+ m_gnutlsSession = NULL;
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+shared_ptr <TLSSocket> TLSSession_GnuTLS::getSocket(const shared_ptr <socket>& sok) {
+
+ return TLSSocket::wrap(dynamicCast <TLSSession>(shared_from_this()), sok);
+}
+
+
+shared_ptr <security::cert::certificateVerifier> TLSSession_GnuTLS::getCertificateVerifier() {
+
+ return m_certVerifier;
+}
+
+
+void TLSSession_GnuTLS::throwTLSException(const string& fname, const int code) {
+
+ std::ostringstream msg;
+
+ msg << fname + "() returned code ";
+ msg << std::hex << code;
+ msg << ": ";
+ msg << gnutls_strerror(code);
+
+ throw exceptions::tls_exception(msg.str());
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp
new file mode 100644
index 0000000..2a7f9d7
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSession.hpp"
+#include "vmime/net/tls/TLSSocket.hpp"
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession_GnuTLS : public TLSSession {
+
+ friend class TLSSocket_GnuTLS;
+
+public:
+
+ TLSSession_GnuTLS(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+ );
+
+ ~TLSSession_GnuTLS();
+
+
+ shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok);
+
+ shared_ptr <security::cert::certificateVerifier> getCertificateVerifier();
+
+private:
+
+ TLSSession_GnuTLS(const TLSSession_GnuTLS&);
+
+ static void throwTLSException(const string& fname, const int code);
+
+
+#ifdef LIBGNUTLS_VERSION
+ gnutls_session_t* m_gnutlsSession;
+#else
+ void* m_gnutlsSession;
+#endif // LIBGNUTLS_VERSION
+
+ shared_ptr <security::cert::certificateVerifier> m_certVerifier;
+ shared_ptr <TLSProperties> m_props;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp
new file mode 100644
index 0000000..53e4eae
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp
@@ -0,0 +1,548 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include <errno.h>
+
+#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <cstring>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+// static
+shared_ptr <TLSSocket> TLSSocket::wrap(
+ const shared_ptr <TLSSession>& session,
+ const shared_ptr <socket>& sok
+)
+{
+ return make_shared <TLSSocket_GnuTLS>(dynamicCast <TLSSession_GnuTLS>(session), sok);
+}
+
+
+TLSSocket_GnuTLS::TLSSocket_GnuTLS(
+ const shared_ptr <TLSSession_GnuTLS>& session,
+ const shared_ptr <socket>& sok
+)
+ : m_session(session),
+ m_wrapped(sok),
+ m_connected(false),
+ m_ex(NULL),
+ m_status(0),
+ m_errno(0) {
+
+ gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);
+
+ gnutls_transport_set_push_function(*m_session->m_gnutlsSession, gnutlsPushFunc);
+ gnutls_transport_set_pull_function(*m_session->m_gnutlsSession, gnutlsPullFunc);
+ gnutls_transport_set_errno_function(*m_session->m_gnutlsSession, gnutlsErrnoFunc);
+}
+
+
+TLSSocket_GnuTLS::~TLSSocket_GnuTLS() {
+
+ resetException();
+
+ try {
+ disconnect();
+ } catch (...) {
+ // Don't throw exception in destructor
+ }
+}
+
+
+void TLSSocket_GnuTLS::connect(const string& address, const port_t port) {
+
+ try {
+
+ m_wrapped->connect(address, port);
+
+ handshake();
+
+ } catch (...) {
+
+ disconnect();
+ throw;
+ }
+}
+
+
+void TLSSocket_GnuTLS::disconnect() {
+
+ if (m_connected) {
+
+ gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR);
+
+ m_wrapped->disconnect();
+
+ m_connected = false;
+ }
+}
+
+
+bool TLSSocket_GnuTLS::isConnected() const {
+
+ return m_wrapped->isConnected() && m_connected;
+}
+
+
+size_t TLSSocket_GnuTLS::getBlockSize() const {
+
+ return 16384; // 16 KB
+}
+
+
+const string TLSSocket_GnuTLS::getPeerName() const {
+
+ return m_wrapped->getPeerName();
+}
+
+
+const string TLSSocket_GnuTLS::getPeerAddress() const {
+
+ return m_wrapped->getPeerAddress();
+}
+
+
+shared_ptr <timeoutHandler> TLSSocket_GnuTLS::getTimeoutHandler() {
+
+ return m_wrapped->getTimeoutHandler();
+}
+
+
+void TLSSocket_GnuTLS::setTracer(const shared_ptr <net::tracer>& tracer) {
+
+ m_wrapped->setTracer(tracer);
+}
+
+
+shared_ptr <net::tracer> TLSSocket_GnuTLS::getTracer() {
+
+ return m_wrapped->getTracer();
+}
+
+
+bool TLSSocket_GnuTLS::waitForRead(const int msecs) {
+
+ return m_wrapped->waitForRead(msecs);
+}
+
+
+bool TLSSocket_GnuTLS::waitForWrite(const int msecs) {
+
+ return m_wrapped->waitForWrite(msecs);
+}
+
+
+void TLSSocket_GnuTLS::receive(string& buffer) {
+
+ const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
+ buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size);
+}
+
+
+void TLSSocket_GnuTLS::send(const string& buffer) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
+}
+
+
+void TLSSocket_GnuTLS::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str));
+}
+
+
+size_t TLSSocket_GnuTLS::receiveRaw(byte_t* buffer, const size_t count) {
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ resetException();
+
+ const ssize_t ret = gnutls_record_recv(
+ *m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(count)
+ );
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_status |= STATUS_WANT_READ;
+ } else {
+ m_status |= STATUS_WANT_WRITE;
+ }
+
+ return 0;
+ }
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_record_recv", static_cast <int>(ret));
+ }
+
+ return static_cast <size_t>(ret);
+}
+
+
+void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ for (size_t size = count ; size > 0 ; ) {
+
+ resetException();
+
+ ssize_t ret = gnutls_record_send(
+ *m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(size)
+ );
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_wrapped->waitForRead();
+ } else {
+ m_wrapped->waitForWrite();
+ }
+
+ continue;
+ }
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret));
+
+ } else {
+
+ buffer += ret;
+ size -= ret;
+ }
+ }
+}
+
+
+size_t TLSSocket_GnuTLS::sendRawNonBlocking(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ resetException();
+
+ ssize_t ret = gnutls_record_send(
+ *m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(count)
+ );
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_status |= STATUS_WANT_READ;
+ } else {
+ m_status |= STATUS_WANT_WRITE;
+ }
+
+ return 0;
+ }
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret));
+ }
+
+ return static_cast <size_t>(ret);
+}
+
+
+unsigned int TLSSocket_GnuTLS::getStatus() const {
+
+ return m_status | m_wrapped->getStatus();
+}
+
+
+void TLSSocket_GnuTLS::handshake() {
+
+ shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
+
+ if (toHandler) {
+ toHandler->resetTimeOut();
+ }
+
+ if (getTracer()) {
+ getTracer()->traceSend("Beginning SSL/TLS handshake");
+ }
+
+ // Start handshaking process
+ try {
+ string peerName = getPeerName();
+
+ gnutls_server_name_set(*m_session->m_gnutlsSession, GNUTLS_NAME_DNS, peerName.c_str(), peerName.size());
+
+ while (true) {
+
+ resetException();
+
+ const int ret = gnutls_handshake(*m_session->m_gnutlsSession);
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_wrapped->waitForRead();
+ } else {
+ m_wrapped->waitForWrite();
+ }
+
+ } else if (ret == GNUTLS_E_INTERRUPTED) {
+
+ // Non-fatal error
+
+ } else {
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_handshake", ret);
+ }
+
+ } else {
+
+ // Successful handshake
+ break;
+ }
+ }
+
+ } catch (...) {
+
+ throw;
+ }
+
+ // Verify server's certificate(s)
+ shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
+
+ if (certs == NULL) {
+ throw exceptions::tls_exception("No peer certificate.");
+ }
+
+ m_session->getCertificateVerifier()->verify(certs, getPeerName());
+
+ m_connected = true;
+}
+
+
+int TLSSocket_GnuTLS::gnutlsErrnoFunc(gnutls_transport_ptr_t trspt) {
+
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+ return sok->m_errno;
+}
+
+
+ssize_t TLSSocket_GnuTLS::gnutlsPushFunc(
+ gnutls_transport_ptr_t trspt,
+ const void* data,
+ size_t len
+) {
+
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+
+ try {
+
+ const ssize_t ret = static_cast <ssize_t>(
+ sok->m_wrapped->sendRawNonBlocking(reinterpret_cast <const byte_t*>(data), len)
+ );
+
+ if (ret == 0) {
+
+ gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN);
+ sok->m_errno = EAGAIN;
+ return -1;
+ }
+
+ return ret;
+
+ } catch (exception& e) {
+
+ // Workaround for non-portable behaviour when throwing C++ exceptions
+ // from C functions (GNU TLS)
+ sok->m_ex = e.clone();
+ return -1;
+ }
+}
+
+
+ssize_t TLSSocket_GnuTLS::gnutlsPullFunc(
+ gnutls_transport_ptr_t trspt,
+ void* data,
+ size_t len
+) {
+
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+
+ try {
+
+ const ssize_t n = static_cast <ssize_t>(
+ sok->m_wrapped->receiveRaw(reinterpret_cast <byte_t*>(data), len)
+ );
+
+ if (n == 0) {
+
+ gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN);
+ sok->m_errno = EAGAIN;
+ return -1;
+ }
+
+ return n;
+
+ } catch (exception& e) {
+
+ // Workaround for non-portable behaviour when throwing C++ exceptions
+ // from C functions (GNU TLS)
+ sok->m_ex = e.clone();
+ return -1;
+ }
+}
+
+
+shared_ptr <security::cert::certificateChain> TLSSocket_GnuTLS::getPeerCertificates() {
+
+ if (getTracer()) {
+ getTracer()->traceSend("Getting peer certificates");
+ }
+
+ unsigned int certCount = 0;
+ const gnutls_datum_t* rawData = gnutls_certificate_get_peers(
+ *m_session->m_gnutlsSession, &certCount
+ );
+
+ if (rawData == NULL) {
+ return null;
+ }
+
+ // Try X.509
+ gnutls_x509_crt_t* x509Certs = new gnutls_x509_crt_t[certCount];
+
+ for (unsigned int i = 0; i < certCount; ++i) {
+
+ gnutls_x509_crt_init(x509Certs + i);
+
+ int res = gnutls_x509_crt_import(x509Certs[i], rawData + i, GNUTLS_X509_FMT_DER);
+
+ if (res < 0) {
+
+ for (unsigned int j = 0 ; j <= i ; ++j) {
+ gnutls_x509_crt_deinit(x509Certs[j]);
+ }
+
+ // XXX more fine-grained error reporting?
+ delete [] x509Certs;
+ return null;
+ }
+ }
+
+ std::vector <shared_ptr <security::cert::certificate> > certs;
+ bool error = false;
+
+ for (unsigned int i = 0 ; i < certCount ; ++i) {
+
+ size_t dataSize = 0;
+
+ gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, NULL, &dataSize);
+
+ std::vector <byte_t> data(dataSize);
+
+ gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, &data[0], &dataSize);
+
+ shared_ptr <security::cert::X509Certificate> cert =
+ security::cert::X509Certificate::import(&data[0], dataSize);
+
+ if (cert != NULL) {
+ certs.push_back(cert);
+ } else {
+ error = true;
+ }
+
+ gnutls_x509_crt_deinit(x509Certs[i]);
+ }
+
+ delete [] x509Certs;
+
+ if (error) {
+ return null;
+ }
+
+ return make_shared <security::cert::certificateChain>(certs);
+}
+
+
+// Following is a workaround for C++ exceptions to pass correctly between
+// C and C++ calls.
+//
+// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions
+// thrown by the socket can not be caught.
+
+void TLSSocket_GnuTLS::throwException() {
+
+ if (m_ex) {
+ throw *m_ex;
+ }
+}
+
+
+void TLSSocket_GnuTLS::resetException() {
+
+ if (m_ex) {
+ delete m_ex;
+ m_ex = NULL;
+ }
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
new file mode 100644
index 0000000..0ac3e70
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
@@ -0,0 +1,129 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSession_GnuTLS;
+
+
+class TLSSocket_GnuTLS : public TLSSocket {
+
+public:
+
+ TLSSocket_GnuTLS(const shared_ptr <TLSSession_GnuTLS>& session, const shared_ptr <socket>& sok);
+ ~TLSSocket_GnuTLS();
+
+
+ void handshake();
+
+ shared_ptr <security::cert::certificateChain> getPeerCertificates();
+
+ // Implementation of 'socket'
+ void connect(const string& address, const port_t port);
+ void disconnect();
+ bool isConnected() const;
+
+ bool waitForRead(const int msecs = 30000);
+ bool waitForWrite(const int msecs = 30000);
+
+ void receive(string& buffer);
+ size_t receiveRaw(byte_t* buffer, const size_t count);
+
+ void send(const string& buffer);
+ void send(const char* str);
+ void sendRaw(const byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const string getPeerName() const;
+ const string getPeerAddress() const;
+
+ shared_ptr <timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const shared_ptr <net::tracer>& tracer);
+ shared_ptr <net::tracer> getTracer();
+
+private:
+
+ void resetException();
+ void throwException();
+
+#ifdef LIBGNUTLS_VERSION
+ static ssize_t gnutlsPushFunc(gnutls_transport_ptr_t trspt, const void* data, size_t len);
+ static ssize_t gnutlsPullFunc(gnutls_transport_ptr_t trspt, void* data, size_t len);
+ static int gnutlsErrnoFunc(gnutls_transport_ptr_t trspt);
+#else
+ static int gnutlsPushFunc(void* trspt, const void* data, size_t len);
+ static int gnutlsPullFunc(void* trspt, void* data, size_t len);
+ static int gnutlsErrnoFunc(void* trspt);
+#endif // LIBGNUTLS_VERSION
+
+
+ shared_ptr <TLSSession_GnuTLS> m_session;
+ shared_ptr <socket> m_wrapped;
+
+ bool m_connected;
+
+ byte_t m_buffer[65536];
+
+ exception* m_ex;
+
+ unsigned int m_status;
+ int m_errno;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp
new file mode 100644
index 0000000..c7b1013
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp
@@ -0,0 +1,169 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/platform.hpp"
+
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# define OPENSSL_API_COMPAT 0x10100000L
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x0907000L
+# include <openssl/conf.h>
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+# include "vmime/utility/sync/autoLock.hpp"
+# include "vmime/utility/sync/criticalSection.hpp"
+#endif
+
+
+// OpenSSL locking callbacks for multithreading support (< v1.1 only)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+namespace {
+
+vmime::shared_ptr <vmime::utility::sync::criticalSection >* g_openSSLMutexes = NULL;
+
+extern "C" void VMime_OpenSSLCallback_lock(int mode, int n, const char* /* file */, int /* line */) {
+
+ if (mode & CRYPTO_LOCK) {
+ g_openSSLMutexes[n]->lock();
+ } else {
+ g_openSSLMutexes[n]->unlock();
+ }
+}
+
+extern "C" unsigned long VMime_OpenSSLCallback_id() {
+
+ return vmime::platform::getHandler()->getThreadId();
+}
+
+}
+
+#endif
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+OpenSSLInitializer::autoInitializer::autoInitializer() {
+
+ // The construction of this unique 'oneTimeInitializer' object will be triggered
+ // by the 'autoInitializer' objects from the other translation units
+ static OpenSSLInitializer::oneTimeInitializer oneTimeInitializer;
+}
+
+
+OpenSSLInitializer::autoInitializer::~autoInitializer() {
+
+}
+
+
+OpenSSLInitializer::oneTimeInitializer::oneTimeInitializer() {
+
+ initialize();
+}
+
+
+OpenSSLInitializer::oneTimeInitializer::~oneTimeInitializer() {
+
+ uninitialize();
+}
+
+
+// static
+void OpenSSLInitializer::initialize() {
+
+#if OPENSSL_VERSION_NUMBER >= 0x0907000L && OPENSSL_VERSION_NUMBER < 0x10100000L
+ OPENSSL_config(NULL);
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+
+ int numMutexes = CRYPTO_num_locks();
+ g_openSSLMutexes = new shared_ptr <vmime::utility::sync::criticalSection>[numMutexes];
+
+ for (int i = 0 ; i < numMutexes ; ++i) {
+ g_openSSLMutexes[i] = vmime::platform::getHandler()->createCriticalSection();
+ }
+
+ CRYPTO_set_locking_callback(VMime_OpenSSLCallback_lock);
+ CRYPTO_set_id_callback(VMime_OpenSSLCallback_id);
+#endif
+
+ // Seed the RNG, in case /dev/urandom is not available. Explicitely calling
+ // RAND_seed() even though /dev/urandom is available is harmless.
+ enum {
+ SEEDSIZE = 256
+ };
+
+ unsigned char seed[SEEDSIZE];
+ vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE);
+ RAND_seed(seed, SEEDSIZE);
+}
+
+
+// static
+void OpenSSLInitializer::uninitialize() {
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ EVP_cleanup();
+ ERR_free_strings();
+
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_id_callback(NULL);
+
+ delete [] g_openSSLMutexes;
+ g_openSSLMutexes = NULL;
+#endif
+
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp
new file mode 100644
index 0000000..3b8496d
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp
@@ -0,0 +1,90 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+#define VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+#include <vector>
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+/** Class responsible for setting up OpenSSL
+ */
+class OpenSSLInitializer {
+
+public:
+
+ /** Automatically initialize OpenSSL
+ */
+ struct autoInitializer {
+
+ autoInitializer();
+ ~autoInitializer();
+ };
+
+protected:
+
+ struct oneTimeInitializer {
+
+ oneTimeInitializer();
+ ~oneTimeInitializer();
+ };
+
+
+ /** Initializes the OpenSSL lib
+ */
+ static void initialize();
+
+ /** Shutdown the OpenSSL lib
+ */
+ static void uninitialize();
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp
new file mode 100644
index 0000000..ea22f1c
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/base.hpp"
+#include "vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSProperties::TLSProperties()
+ : m_data(make_shared <TLSProperties_OpenSSL>()) {
+
+ setCipherSuite(CIPHERSUITE_DEFAULT);
+}
+
+
+TLSProperties::TLSProperties(const TLSProperties& props)
+ : object(),
+ m_data(make_shared <TLSProperties_OpenSSL>()) {
+
+ *dynamicCast <TLSProperties_OpenSSL>(m_data) = *dynamicCast <TLSProperties_OpenSSL>(props.m_data);
+}
+
+
+void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) {
+
+ switch (cipherSuite) {
+
+ case CIPHERSUITE_HIGH:
+
+ setCipherSuite("HIGH:!ADH:@STRENGTH");
+ break;
+
+ case CIPHERSUITE_MEDIUM:
+
+ setCipherSuite("MEDIUM:!ADH:@STRENGTH");
+ break;
+
+ case CIPHERSUITE_LOW:
+
+ setCipherSuite("LOW:!ADH:@STRENGTH");
+ break;
+
+ default:
+ case CIPHERSUITE_DEFAULT:
+
+ setCipherSuite("DEFAULT:!ADH:@STRENGTH");
+ break;
+ }
+}
+
+
+void TLSProperties::setCipherSuite(const string& cipherSuite) {
+
+ dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite = cipherSuite;
+}
+
+
+const string TLSProperties::getCipherSuite() const {
+
+ return dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite;
+}
+
+
+
+TLSProperties_OpenSSL& TLSProperties_OpenSSL::operator=(const TLSProperties_OpenSSL& other) {
+
+ cipherSuite = other.cipherSuite;
+
+ return *this;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp
new file mode 100644
index 0000000..8304df2
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSProperties_OpenSSL : public object {
+
+public:
+
+ TLSProperties_OpenSSL& operator=(const TLSProperties_OpenSSL& other);
+
+
+ string cipherSuite;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp
new file mode 100644
index 0000000..019341c
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp
@@ -0,0 +1,147 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/security/cert/certificateException.hpp"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+static OpenSSLInitializer::autoInitializer openSSLInitializer;
+
+
+// static
+shared_ptr <TLSSession> TLSSession::create(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+) {
+
+ return make_shared <TLSSession_OpenSSL>(cv, props);
+}
+
+
+TLSSession_OpenSSL::TLSSession_OpenSSL(
+ const shared_ptr <vmime::security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+)
+ : m_sslctx(0),
+ m_certVerifier(cv),
+ m_props(props) {
+
+ m_sslctx = SSL_CTX_new(SSLv23_client_method());
+ SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
+ SSL_CTX_set_mode(m_sslctx, SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_cipher_list(m_sslctx, m_props->getCipherSuite().c_str());
+ SSL_CTX_set_session_cache_mode(m_sslctx, SSL_SESS_CACHE_OFF);
+}
+
+
+TLSSession_OpenSSL::TLSSession_OpenSSL(const TLSSession_OpenSSL&)
+ : TLSSession() {
+
+ // Not used
+}
+
+
+TLSSession_OpenSSL::~TLSSession_OpenSSL() {
+
+ SSL_CTX_free(m_sslctx);
+}
+
+
+shared_ptr <TLSSocket> TLSSession_OpenSSL::getSocket(const shared_ptr <socket>& sok) {
+
+ return TLSSocket::wrap(dynamicCast <TLSSession>(shared_from_this()), sok);
+}
+
+
+shared_ptr <security::cert::certificateVerifier> TLSSession_OpenSSL::getCertificateVerifier() {
+
+ return m_certVerifier;
+}
+
+
+void TLSSession_OpenSSL::usePrivateKeyFile(const vmime::string& keyfile) {
+
+ ERR_clear_error();
+
+ if (SSL_CTX_use_PrivateKey_file(m_sslctx, keyfile.c_str(), SSL_FILETYPE_PEM) != 1) {
+
+ unsigned long errCode = ERR_get_error();
+ char buffer[256];
+ ERR_error_string_n(errCode, buffer, sizeof(buffer));
+ vmime::string sslErr(buffer);
+ std::ostringstream oss;
+ oss << "Error loading private key from file " << keyfile;
+ oss << " - msg: " << sslErr;
+ throw security::cert::certificateException(oss.str());
+ }
+}
+
+
+void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile) {
+
+ ERR_clear_error();
+
+ if (SSL_CTX_use_certificate_chain_file(m_sslctx, chainFile.c_str()) != 1) {
+
+ unsigned long errCode = ERR_get_error();
+ char buffer[256];
+ ERR_error_string_n(errCode, buffer, sizeof(buffer));
+ vmime::string sslErr(buffer);
+ std::ostringstream oss;
+ oss << "Error loading certificate from file " << chainFile;
+ oss << " - msg: " << sslErr;
+ throw security::cert::certificateException(oss.str());
+ }
+}
+
+
+SSL_CTX* TLSSession_OpenSSL::getContext() const {
+
+ return m_sslctx;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp
new file mode 100644
index 0000000..518216b
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp
@@ -0,0 +1,109 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSession.hpp"
+#include "vmime/net/tls/TLSSocket.hpp"
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+#include <openssl/ssl.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession_OpenSSL : public TLSSession {
+
+ friend class TLSSocket_OpenSSL;
+
+public:
+
+ TLSSession_OpenSSL(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+ );
+
+ ~TLSSession_OpenSSL();
+
+
+ shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok);
+
+ shared_ptr <security::cert::certificateVerifier> getCertificateVerifier();
+
+
+ /** Set the private key to use if server requires a client certificate.
+ *
+ * @param keyfile path to the private key in PEM format
+ */
+ void usePrivateKeyFile(const vmime::string& keyfile);
+
+ /** Supply the certificate chain to present if requested by server.
+ *
+ * @param chainFile File in PEM format holding certificate chain
+ */
+ void useCertificateChainFile(const vmime::string& chainFile);
+
+ /** Get a pointer to the SSL_CTX used for this session.
+ *
+ * @return the SSL_CTX used for all connections created with this session
+ */
+ SSL_CTX* getContext() const;
+
+private:
+
+ TLSSession_OpenSSL(const TLSSession_OpenSSL&);
+
+ SSL_CTX* m_sslctx;
+
+ shared_ptr <security::cert::certificateVerifier> m_certVerifier;
+ shared_ptr <TLSProperties> m_props;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp
new file mode 100644
index 0000000..978f0ca
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp
@@ -0,0 +1,761 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <vector>
+#include <cstring>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+static OpenSSLInitializer::autoInitializer openSSLInitializer;
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+// static
+BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod = {
+ 100 | BIO_TYPE_SOURCE_SINK,
+ "vmime::socket glue",
+ TLSSocket_OpenSSL::bio_write,
+ TLSSocket_OpenSSL::bio_read,
+ TLSSocket_OpenSSL::bio_puts,
+ NULL, // gets
+ TLSSocket_OpenSSL::bio_ctrl,
+ TLSSocket_OpenSSL::bio_create,
+ TLSSocket_OpenSSL::bio_destroy,
+ 0
+};
+
+#define BIO_set_init(b, val) b->init = val
+#define BIO_set_data(b, val) b->ptr = val
+#define BIO_set_num(b, val) b->num = val
+#define BIO_set_flags(b, val) b->flags = val
+#define BIO_set_shutdown(b, val) b->shutdown = val
+#define BIO_get_init(b) b->init
+#define BIO_get_data(b) b->ptr
+#define BIO_get_shutdown(b) b->shutdown
+
+#else
+
+#define BIO_set_num(b, val)
+
+#endif
+
+
+
+// static
+shared_ptr <TLSSocket> TLSSocket::wrap(
+ const shared_ptr <TLSSession>& session,
+ const shared_ptr <socket>& sok
+) {
+
+ return make_shared <TLSSocket_OpenSSL>(dynamicCast <TLSSession_OpenSSL>(session), sok);
+}
+
+
+TLSSocket_OpenSSL::TLSSocket_OpenSSL(
+ const shared_ptr <TLSSession_OpenSSL>& session,
+ const shared_ptr <socket>& sok
+)
+ : m_session(session),
+ m_wrapped(sok),
+ m_connected(false),
+ m_ssl(0),
+ m_status(0),
+ m_ex() {
+
+}
+
+
+TLSSocket_OpenSSL::~TLSSocket_OpenSSL() {
+
+ try {
+ disconnect();
+ } catch (...) {
+ // Don't throw in destructor
+ }
+}
+
+
+void TLSSocket_OpenSSL::createSSLHandle() {
+
+ if (m_wrapped->isConnected()) {
+ string peerName = getPeerName();
+
+ if (peerName.empty()) {
+ throw exceptions::tls_exception("Unknown host name, will not be able to set SNI");
+ }
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+ BIO* sockBio = BIO_new(&sm_customBIOMethod);
+ sockBio->ptr = this;
+ sockBio->init = 1;
+
+#else
+
+ BIO_METHOD* bioMeth = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "vmime::socket glue");
+
+ if (!bioMeth) {
+ BIO_meth_free(bioMeth);
+ throw exceptions::tls_exception("BIO_meth_new() failed");
+ }
+
+ BIO_meth_set_write(bioMeth, TLSSocket_OpenSSL::bio_write);
+ BIO_meth_set_read(bioMeth, TLSSocket_OpenSSL::bio_read);
+ BIO_meth_set_puts(bioMeth, TLSSocket_OpenSSL::bio_puts);
+ BIO_meth_set_ctrl(bioMeth, TLSSocket_OpenSSL::bio_ctrl);
+ BIO_meth_set_create(bioMeth, TLSSocket_OpenSSL::bio_create);
+ BIO_meth_set_destroy(bioMeth, TLSSocket_OpenSSL::bio_destroy);
+
+ BIO* sockBio = BIO_new(bioMeth);
+ BIO_set_data(sockBio, this);
+ BIO_set_init(sockBio, 1);
+
+#endif
+
+ if (!sockBio) {
+ throw exceptions::tls_exception("BIO_new() failed");
+ }
+
+ m_ssl = SSL_new(m_session->getContext());
+
+ if (!m_ssl) {
+ BIO_free(sockBio);
+ throw exceptions::tls_exception("Cannot create SSL object");
+ }
+
+ SSL_set_bio(m_ssl, sockBio, sockBio);
+ SSL_set_tlsext_host_name(m_ssl, peerName.c_str());
+ SSL_set_connect_state(m_ssl);
+ SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ } else {
+
+ throw exceptions::tls_exception("Unconnected socket error");
+ }
+}
+
+
+void TLSSocket_OpenSSL::connect(const string& address, const port_t port) {
+
+ try {
+
+ m_wrapped->connect(address, port);
+
+ createSSLHandle();
+
+ handshake();
+
+ } catch (...) {
+
+ disconnect();
+ throw;
+ }
+}
+
+
+void TLSSocket_OpenSSL::disconnect() {
+
+ if (m_ssl) {
+
+ // Don't shut down the socket more than once.
+ int shutdownState = SSL_get_shutdown(m_ssl);
+ bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
+
+ if (!shutdownSent) {
+ SSL_shutdown(m_ssl);
+ }
+
+ SSL_free(m_ssl);
+ m_ssl = 0;
+ }
+
+ if (m_connected) {
+ m_connected = false;
+ m_wrapped->disconnect();
+ }
+}
+
+
+bool TLSSocket_OpenSSL::isConnected() const {
+
+ return m_wrapped->isConnected() && m_connected;
+}
+
+
+size_t TLSSocket_OpenSSL::getBlockSize() const {
+
+ return 16384; // 16 KB
+}
+
+
+const string TLSSocket_OpenSSL::getPeerName() const {
+
+ return m_wrapped->getPeerName();
+}
+
+
+const string TLSSocket_OpenSSL::getPeerAddress() const {
+
+ return m_wrapped->getPeerAddress();
+}
+
+
+shared_ptr <timeoutHandler> TLSSocket_OpenSSL::getTimeoutHandler() {
+
+ return m_wrapped->getTimeoutHandler();
+}
+
+
+void TLSSocket_OpenSSL::setTracer(const shared_ptr <net::tracer>& tracer) {
+
+ m_wrapped->setTracer(tracer);
+}
+
+
+shared_ptr <net::tracer> TLSSocket_OpenSSL::getTracer() {
+
+ return m_wrapped->getTracer();
+}
+
+
+bool TLSSocket_OpenSSL::waitForRead(const int msecs) {
+
+ return m_wrapped->waitForRead(msecs);
+}
+
+
+bool TLSSocket_OpenSSL::waitForWrite(const int msecs) {
+
+ return m_wrapped->waitForWrite(msecs);
+}
+
+
+void TLSSocket_OpenSSL::receive(string& buffer) {
+
+ const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
+
+ if (size != 0) {
+ buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size);
+ } else {
+ buffer.clear();
+ }
+}
+
+
+void TLSSocket_OpenSSL::send(const string& buffer) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
+}
+
+
+void TLSSocket_OpenSSL::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str));
+}
+
+
+size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count) {
+
+ if (!m_ssl) {
+ throw exceptions::socket_not_connected_exception();
+ }
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ ERR_clear_error();
+ int rc = SSL_read(m_ssl, buffer, static_cast <int>(count));
+
+ if (m_ex.get()) {
+ internalThrow();
+ }
+
+ if (rc <= 0) {
+
+ int error = SSL_get_error(m_ssl, rc);
+
+ if (error == SSL_ERROR_WANT_WRITE) {
+ m_status |= STATUS_WANT_WRITE;
+ return 0;
+ } else if (error == SSL_ERROR_WANT_READ) {
+ m_status |= STATUS_WANT_READ;
+ return 0;
+ }
+
+ handleError(rc);
+ }
+
+ return rc;
+}
+
+
+void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count) {
+
+ if (!m_ssl) {
+ throw exceptions::socket_not_connected_exception();
+ }
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ for (size_t size = count ; size > 0 ; ) {
+
+ ERR_clear_error();
+ int rc = SSL_write(m_ssl, buffer, static_cast <int>(size));
+
+ if (rc <= 0) {
+
+ int error = SSL_get_error(m_ssl, rc);
+
+ if (error == SSL_ERROR_WANT_READ) {
+ m_wrapped->waitForRead();
+ continue;
+ } else if (error == SSL_ERROR_WANT_WRITE) {
+ m_wrapped->waitForWrite();
+ continue;
+ }
+
+ handleError(rc);
+
+ } else {
+
+ buffer += rc;
+ size -= rc;
+ }
+ }
+}
+
+
+size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count) {
+
+ if (!m_ssl) {
+ throw exceptions::socket_not_connected_exception();
+ }
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ ERR_clear_error();
+ int rc = SSL_write(m_ssl, buffer, static_cast <int>(count));
+
+ if (m_ex.get()) {
+ internalThrow();
+ }
+
+ if (rc <= 0) {
+
+ int error = SSL_get_error(m_ssl, rc);
+
+ if (error == SSL_ERROR_WANT_WRITE) {
+ m_status |= STATUS_WANT_WRITE;
+ return 0;
+ } else if (error == SSL_ERROR_WANT_READ) {
+ m_status |= STATUS_WANT_READ;
+ return 0;
+ }
+
+ handleError(rc);
+ }
+
+ return rc;
+}
+
+
+void TLSSocket_OpenSSL::handshake() {
+
+ shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
+
+ if (toHandler) {
+ toHandler->resetTimeOut();
+ }
+
+ if (getTracer()) {
+ getTracer()->traceSend("Beginning SSL/TLS handshake");
+ }
+
+ // Start handshaking process
+ if (!m_ssl) {
+ createSSLHandle();
+ }
+
+ try {
+
+ int rc;
+
+ ERR_clear_error();
+
+ while ((rc = SSL_do_handshake(m_ssl)) <= 0) {
+
+ const int err = SSL_get_error(m_ssl, rc);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ m_wrapped->waitForRead();
+ } else if (err == SSL_ERROR_WANT_WRITE) {
+ m_wrapped->waitForWrite();
+ } else {
+ handleError(rc);
+ }
+
+ // Check whether the time-out delay is elapsed
+ if (toHandler && toHandler->isTimeOut()) {
+
+ if (!toHandler->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ toHandler->resetTimeOut();
+ }
+
+ ERR_clear_error();
+ }
+
+ } catch (...) {
+
+ throw;
+ }
+
+ // Verify server's certificate(s)
+ shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
+
+ if (!certs) {
+ throw exceptions::tls_exception("No peer certificate.");
+ }
+
+ m_session->getCertificateVerifier()->verify(certs, getPeerName());
+
+ m_connected = true;
+}
+
+
+shared_ptr <security::cert::certificateChain> TLSSocket_OpenSSL::getPeerCertificates() {
+
+ if (getTracer()) {
+ getTracer()->traceSend("Getting peer certificates");
+ }
+
+ STACK_OF(X509)* chain = SSL_get_peer_cert_chain(m_ssl);
+
+ if (chain == NULL) {
+ return null;
+ }
+
+ int certCount = sk_X509_num(chain);
+
+ if (certCount == 0) {
+ return null;
+ }
+
+ bool error = false;
+ std::vector <shared_ptr <security::cert::certificate> > certs;
+
+ for (int i = 0; i < certCount && !error; i++) {
+
+ shared_ptr <vmime::security::cert::X509Certificate> cert =
+ vmime::security::cert::X509Certificate_OpenSSL::importInternal(sk_X509_value(chain, i));
+
+ if (cert) {
+ certs.push_back(cert);
+ } else {
+ error = true;
+ }
+ }
+
+ if (error) {
+ return null;
+ }
+
+ return make_shared <security::cert::certificateChain>(certs);
+}
+
+
+void TLSSocket_OpenSSL::internalThrow() {
+
+ if (m_ex.get()) {
+ throw *m_ex;
+ }
+}
+
+
+void TLSSocket_OpenSSL::handleError(int rc) {
+
+ if (rc > 0) {
+ return;
+ }
+
+ internalThrow();
+
+ int sslError = SSL_get_error(m_ssl, rc);
+ long lastError = ERR_get_error();
+
+ switch (sslError) {
+
+ case SSL_ERROR_ZERO_RETURN:
+
+ disconnect();
+ return;
+
+ case SSL_ERROR_SYSCALL: {
+
+ if (lastError == 0) {
+
+ if (rc == 0) {
+
+ throw exceptions::tls_exception("SSL connection unexpectedly closed");
+
+ } else {
+
+ std::ostringstream oss;
+ oss << "The BIO reported an error: " << rc;
+ oss.flush();
+ throw exceptions::tls_exception(oss.str());
+ }
+ }
+
+ break;
+ }
+
+ case SSL_ERROR_WANT_READ:
+
+ BIO_set_retry_read(SSL_get_rbio(m_ssl));
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+
+ BIO_set_retry_write(SSL_get_wbio(m_ssl));
+ break;
+
+ // This happens only for BIOs of type BIO_s_connect() or BIO_s_accept()
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ // SSL_CTX_set_client_cert_cb related, not used
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ default:
+
+ if (lastError == 0) {
+
+ throw exceptions::tls_exception("Unexpected SSL IO error");
+
+ } else {
+
+ char buffer[256];
+ ERR_error_string_n(lastError, buffer, sizeof(buffer));
+ vmime::string msg(buffer);
+ throw exceptions::tls_exception(msg);
+ }
+
+ break;
+ }
+}
+
+
+unsigned int TLSSocket_OpenSSL::getStatus() const {
+
+ return m_status;
+}
+
+
+// Implementation of custom BIO methods
+
+
+// static
+int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len) {
+
+ BIO_clear_retry_flags(bio);
+
+ if (buf == NULL || len <= 0) {
+ return -1;
+ }
+
+ TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio));
+
+ if (!BIO_get_init(bio) || !sok) {
+ return -1;
+ }
+
+ try {
+
+ const size_t n = sok->m_wrapped->sendRawNonBlocking(
+ reinterpret_cast <const byte_t*>(buf), len
+ );
+
+ if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) {
+ BIO_set_retry_write(bio);
+ return -1;
+ }
+
+ return static_cast <int>(n);
+
+ } catch (exception& e) {
+
+ // Workaround for passing C++ exceptions from C BIO functions
+ sok->m_ex.reset(e.clone());
+ return -1;
+ }
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len) {
+
+ BIO_clear_retry_flags(bio);
+
+ if (buf == NULL || len <= 0) {
+ return -1;
+ }
+
+ TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio));
+
+ if (!BIO_get_init(bio) || !sok) {
+ return -1;
+ }
+
+ try {
+
+ const size_t n = sok->m_wrapped->receiveRaw(
+ reinterpret_cast <byte_t*>(buf), len
+ );
+
+ if (n == 0 || sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) {
+ BIO_set_retry_read(bio);
+ return -1;
+ }
+
+ return static_cast <int>(n);
+
+ } catch (exception& e) {
+
+ // Workaround for passing C++ exceptions from C BIO functions
+ sok->m_ex.reset(e.clone());
+ return -1;
+ }
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_puts(BIO* bio, const char* str) {
+
+ return bio_write(bio, str, static_cast <int>(strlen(str)));
+}
+
+
+// static
+long TLSSocket_OpenSSL::bio_ctrl(BIO* bio, int cmd, long num, void* /* ptr */) {
+
+ long ret = 1;
+
+ switch (cmd) {
+
+ case BIO_CTRL_INFO:
+
+ ret = 0;
+ break;
+
+ case BIO_CTRL_GET_CLOSE:
+
+ ret = BIO_get_shutdown(bio);
+ break;
+
+ case BIO_CTRL_SET_CLOSE:
+
+ BIO_set_shutdown(bio, static_cast <int>(num));
+ break;
+
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+
+ ret = 0;
+ break;
+
+ case BIO_CTRL_DUP:
+ case BIO_CTRL_FLUSH:
+
+ ret = 1;
+ break;
+
+ default:
+
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_create(BIO* bio) {
+
+ BIO_set_init(bio, 0);
+ BIO_set_num(bio, 0);
+ BIO_set_data(bio, NULL);
+ BIO_set_flags(bio, 0);
+
+ return 1;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_destroy(BIO* bio) {
+
+ if (!bio) {
+ return 0;
+ }
+
+ if (BIO_get_shutdown(bio)) {
+ BIO_set_data(bio, NULL);
+ BIO_set_init(bio, 0);
+ BIO_set_flags(bio, 0);
+ }
+
+ return 1;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
new file mode 100644
index 0000000..e30df68
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
@@ -0,0 +1,142 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+#include <memory>
+
+#include <openssl/ssl.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSession_OpenSSL;
+
+
+class TLSSocket_OpenSSL : public TLSSocket {
+
+public:
+
+ TLSSocket_OpenSSL(
+ const shared_ptr <TLSSession_OpenSSL>& session,
+ const shared_ptr <socket>& sok
+ );
+
+ ~TLSSocket_OpenSSL();
+
+
+ void handshake();
+
+ shared_ptr <security::cert::certificateChain> getPeerCertificates();
+
+ // Implementation of 'socket'
+ void connect(const string& address, const port_t port);
+ void disconnect();
+ bool isConnected() const;
+
+ bool waitForRead(const int msecs = 30000);
+ bool waitForWrite(const int msecs = 30000);
+
+ void receive(string& buffer);
+ size_t receiveRaw(byte_t* buffer, const size_t count);
+
+ void send(const string& buffer);
+ void send(const char* str);
+ void sendRaw(const byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const string getPeerName() const;
+ const string getPeerAddress() const;
+
+ shared_ptr <timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const shared_ptr <net::tracer>& tracer);
+ shared_ptr <net::tracer> getTracer();
+
+private:
+
+ static BIO_METHOD sm_customBIOMethod;
+
+ static int bio_write(BIO* bio, const char* buf, int len);
+ static int bio_read(BIO* bio, char* buf, int len);
+ static int bio_puts(BIO* bio, const char* str);
+ static int bio_gets(BIO* bio, char* buf, int len);
+ static long bio_ctrl(BIO* bio, int cmd, long num, void* ptr);
+ static int bio_create(BIO* bio);
+ static int bio_destroy(BIO* bio);
+
+ void createSSLHandle();
+
+ void internalThrow();
+ void handleError(int rc);
+
+
+ shared_ptr <TLSSession_OpenSSL> m_session;
+
+ shared_ptr <socket> m_wrapped;
+
+ bool m_connected;
+
+ byte_t m_buffer[65536];
+
+ SSL* m_ssl;
+
+ unsigned int m_status;
+
+ // Last exception thrown from C BIO functions
+ scoped_ptr <exception> m_ex;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tracer.cpp b/vmime-master/src/vmime/net/tracer.cpp
new file mode 100644
index 0000000..66afb36
--- /dev/null
+++ b/vmime-master/src/vmime/net/tracer.cpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "tracer.hpp"
+
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+
+
+void tracer::traceReceiveBytes(const size_t count, const string& state) {
+
+ std::ostringstream oss;
+ oss << "{...";
+
+ if (!state.empty()) {
+ oss << state << ": ";
+ }
+
+ oss << count << " bytes of data...}";
+
+ traceReceive(oss.str());
+}
+
+
+void tracer::traceSendBytes(const size_t count, const string& state) {
+
+ std::ostringstream oss;
+ oss << "{...";
+
+ if (!state.empty()) {
+ oss << state << ": ";
+ }
+
+ oss << count << " bytes of data...}";
+
+ traceSend(oss.str());
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/tracer.hpp b/vmime-master/src/vmime/net/tracer.hpp
new file mode 100644
index 0000000..7472463
--- /dev/null
+++ b/vmime-master/src/vmime/net/tracer.hpp
@@ -0,0 +1,110 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TRACER_HPP_INCLUDED
+#define VMIME_NET_TRACER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class service;
+
+
+/** Base class for an object used to trace network communication
+ * between the client and the server.
+ */
+class VMIME_EXPORT tracer : public object {
+
+public:
+
+ virtual ~tracer() {
+
+ }
+
+ /** Trace raw bytes which have been received.
+ *
+ * @param count number of bytes
+ * @param state protocol state (eg. "SASL exchange"), or empty
+ */
+ virtual void traceReceiveBytes(const size_t count, const string& state = "");
+
+ /** Trace raw bytes which have been sent.
+ *
+ * @param count number of bytes
+ * @param state protocol state (eg. "SASL exchange"), or empty
+ */
+ virtual void traceSendBytes(const size_t count, const string& state = "");
+
+ /** Trace a command line which has been sent.
+ *
+ * @param line command line
+ */
+ virtual void traceSend(const string& line) = 0;
+
+ /** Trace a response line which has been received.
+ *
+ * @param line response line
+ */
+ virtual void traceReceive(const string& line) = 0;
+};
+
+
+/** A class to create 'tracer' objects.
+ */
+class VMIME_EXPORT tracerFactory : public object {
+
+public:
+
+ virtual ~tracerFactory() {
+
+ }
+
+ /** Creates a tracer for the specified service.
+ *
+ * @param serv messaging service
+ * @param connectionId an identifier for the connection to distinguate between
+ * different connections used by a service
+ * @return a new tracer
+ */
+ virtual shared_ptr <tracer> create(const shared_ptr <service>& serv, const int connectionId) = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_TRACER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/transport.cpp b/vmime-master/src/vmime/net/transport.cpp
new file mode 100644
index 0000000..0991302
--- /dev/null
+++ b/vmime-master/src/vmime/net/transport.cpp
@@ -0,0 +1,265 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/transport.hpp"
+
+#include "vmime/utility/stream.hpp"
+#include "vmime/mailboxList.hpp"
+#include "vmime/message.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/messageId.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+transport::transport(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+)
+ : service(sess, infos, auth) {
+
+}
+
+
+shared_ptr <headerField> transport::processHeaderField(const shared_ptr <headerField>& field) {
+
+ if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::BCC)) {
+
+ // Remove Bcc headers from the message, as required by the RFC.
+ // Some SMTP server automatically strip this header (Postfix, qmail),
+ // and others have an option for this (Exim).
+ return null;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::RETURN_PATH)) {
+
+ // RFC-2821: Return-Path header is added by the final transport system
+ // that delivers the message to its recipient. Then, it should not be
+ // transmitted to MSA.
+ return null;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::ORIGINAL_RECIPIENT)) {
+
+ // RFC-2298: Delivering MTA may add the Original-Recipient header and
+ // discard existing one; so, no need to send it.
+ return null;
+ }
+
+ // Leave the header field as is
+ return field;
+}
+
+
+void transport::processHeader(const shared_ptr <header>& header) {
+
+ if (header->getFieldCount() == 0) {
+ return;
+ }
+
+ // Remove/replace fields
+ for (size_t idx = header->getFieldCount() ; idx != 0 ; --idx) {
+
+ shared_ptr <headerField> field = header->getFieldAt(idx - 1);
+ shared_ptr <headerField> newField = processHeaderField(field);
+
+ if (newField == NULL) {
+ header->removeField(field);
+ } else if (newField != field) {
+ header->replaceField(field, newField);
+ }
+ }
+
+ // Add missing header fields
+ // -- Date
+ if (!header->hasField(fields::DATE)) {
+ header->Date()->setValue(datetime::now());
+ }
+
+ // -- Mime-Version
+ if (!header->hasField(fields::MIME_VERSION)) {
+ header->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION));
+ }
+
+ // -- Message-Id
+ if (!header->hasField(fields::MESSAGE_ID)) {
+ header->MessageId()->setValue(messageId::generateId());
+ }
+}
+
+
+static void extractMailboxes(
+ mailboxList& recipients,
+ const addressList& list
+) {
+
+ for (size_t i = 0 ; i < list.getAddressCount() ; ++i) {
+
+ shared_ptr <mailbox> mbox = dynamicCast <mailbox>(list.getAddressAt(i)->clone());
+
+ if (mbox) {
+ recipients.appendMailbox(mbox);
+ }
+ }
+}
+
+
+void transport::send(
+ const shared_ptr <vmime::message>& msg,
+ utility::progressListener* progress,
+ const dsnAttributes& dsnAttrs
+) {
+
+ // Extract expeditor
+ shared_ptr <mailbox> fromMbox =
+ msg->getHeader()->findFieldValue <mailbox>(fields::FROM);
+
+ if (!fromMbox) {
+ throw exceptions::no_expeditor();
+ }
+
+ mailbox expeditor = *fromMbox;
+
+ // Extract sender
+ shared_ptr <mailbox> senderMbox =
+ msg->getHeader()->findFieldValue <mailbox>(fields::SENDER);
+
+ mailbox sender;
+
+ if (!senderMbox) {
+ sender = expeditor;
+ } else {
+ sender = *senderMbox;
+ }
+
+ // Extract recipients
+ mailboxList recipients;
+
+ // -- "To" field
+ shared_ptr <addressList> addresses =
+ msg->getHeader()->findFieldValue <addressList>(fields::TO);
+
+ if (addresses) {
+ extractMailboxes(recipients, *addresses);
+ }
+
+ // -- "Cc" field
+ addresses = msg->getHeader()->findFieldValue <addressList>(fields::CC);
+
+ if (addresses) {
+ extractMailboxes(recipients, *addresses);
+ }
+
+ // -- "Bcc" field
+ addresses = msg->getHeader()->findFieldValue <addressList>(fields::BCC);
+
+ if (addresses) {
+ extractMailboxes(recipients, *addresses);
+ }
+
+ // Process message header by removing fields that should be removed
+ // before transmitting the message to MSA, and adding missing fields
+ // which are required/recommended by the RFCs.
+ shared_ptr <header> hdr = vmime::clone(msg->getHeader());
+ processHeader(hdr);
+
+ // To avoid cloning message body (too much overhead), use processed
+ // header during the time we are generating the message to a stream.
+ // Revert it back to original header after.
+ struct XChangeMsgHeader {
+
+ XChangeMsgHeader(
+ const shared_ptr <vmime::message>& _msg,
+ const shared_ptr <vmime::header>& _hdr
+ )
+ : msg(_msg),
+ hdr(msg->getHeader()) {
+
+ // Set new header
+ msg->setHeader(_hdr);
+ }
+
+ ~XChangeMsgHeader() {
+
+ // Revert original header
+ msg->setHeader(hdr);
+ }
+
+ private:
+
+ shared_ptr <vmime::message> msg;
+ shared_ptr <vmime::header> hdr;
+
+ } headerExchanger(msg, hdr);
+
+ send(msg, expeditor, recipients, progress, sender, dsnAttrs);
+}
+
+
+void transport::send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& dsnAttrs
+) {
+
+ // 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, sender,
+ dsnAttrs);
+}
+
+
+transport::Type transport::getType() const {
+
+ return TYPE_TRANSPORT;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/transport.hpp b/vmime-master/src/vmime/net/transport.hpp
new file mode 100644
index 0000000..daa4717
--- /dev/null
+++ b/vmime-master/src/vmime/net/transport.hpp
@@ -0,0 +1,152 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TRANSPORT_HPP_INCLUDED
+#define VMIME_NET_TRANSPORT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/dsnAttributes.hpp"
+#include "vmime/net/service.hpp"
+#include "vmime/utility/stream.hpp"
+
+#include "vmime/mailboxList.hpp"
+
+
+namespace vmime {
+
+class header;
+class headerField;
+class message;
+class mailbox;
+class mailboxList;
+
+namespace net {
+
+
+/** A transport service.
+ * Encapsulate protocols that can send messages.
+ */
+class VMIME_EXPORT transport : public service {
+
+protected:
+
+ transport(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+public:
+
+ /** Send a message over this transport service.
+ * The default implementation simply generates the whole message into
+ * a string buffer and "streams" it via a inputStreamStringAdapter.
+ *
+ * @param msg message to send
+ * @param progress progress listener, or NULL if not used
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ virtual void send(
+ const shared_ptr <vmime::message>& msg,
+ utility::progressListener* progress = NULL,
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ /** Send a message over this transport service.
+ *
+ * @param expeditor expeditor mailbox
+ * @param recipients list of recipient mailboxes
+ * @param is input stream providing message data (header + body)
+ * @param size size of the message data
+ * @param progress progress listener, or NULL if not used
+ * @param sender envelope sender (if empty, expeditor will be used)
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ virtual void send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ ) = 0;
+
+ /** Send a message over this transport service.
+ * The default implementation simply generates the whole message into
+ * a string buffer and "streams" it via a inputStreamStringAdapter.
+ *
+ * @param msg message to send
+ * @param expeditor expeditor mailbox
+ * @param recipients list of recipient mailboxes
+ * @param progress progress listener, or NULL if not used
+ * @param sender envelope sender (if empty, expeditor will be used)
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ virtual void send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+
+ Type getType() const;
+
+protected:
+
+ /** Called by processHeader().
+ * Decides what to do with the specified header field.
+ *
+ * @return NULL if the header should be removed, a reference to a new headerField
+ * if the field is to be replaced, or a reference to the same headerField
+ * that was passed if the field should be left as is
+ */
+ shared_ptr <headerField> processHeaderField(const shared_ptr <headerField>& field);
+
+ /** Prepares the header before transmitting the message.
+ * Removes headers that should not be present (eg. "Bcc", "Return-Path"),
+ * or adds missing headers that are required/recommended by the RFCs.
+ * The header is modified inline.
+ *
+ * @param header headers to process
+ */
+ void processHeader(const shared_ptr <header>& header);
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_TRANSPORT_HPP_INCLUDED