/gnu/

gram/diff/vmime-master/src/vmime'>vmime/net
diff options
context:
space:
mode:
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;
+