diff options
Diffstat (limited to '')
-rw-r--r-- | vmime/net/folder.hpp | 10 | ||||
-rw-r--r-- | vmime/net/folderStatus.hpp | 68 | ||||
-rw-r--r-- | vmime/net/imap/IMAPConnection.hpp | 9 | ||||
-rw-r--r-- | vmime/net/imap/IMAPFolder.hpp | 24 | ||||
-rw-r--r-- | vmime/net/imap/IMAPFolderStatus.hpp | 117 | ||||
-rw-r--r-- | vmime/net/imap/IMAPMessage.hpp | 19 | ||||
-rw-r--r-- | vmime/net/imap/IMAPParser.hpp | 837 | ||||
-rw-r--r-- | vmime/net/imap/IMAPStore.hpp | 1 | ||||
-rw-r--r-- | vmime/net/imap/IMAPUtils.hpp | 15 | ||||
-rw-r--r-- | vmime/net/maildir/maildirFolder.hpp | 1 | ||||
-rw-r--r-- | vmime/net/maildir/maildirFolderStatus.hpp | 70 | ||||
-rw-r--r-- | vmime/net/maildir/maildirMessage.hpp | 2 | ||||
-rw-r--r-- | vmime/net/message.hpp | 5 | ||||
-rw-r--r-- | vmime/net/pop3/POP3Folder.hpp | 1 | ||||
-rw-r--r-- | vmime/net/pop3/POP3FolderStatus.hpp | 70 | ||||
-rw-r--r-- | vmime/net/pop3/POP3Message.hpp | 2 |
16 files changed, 971 insertions, 280 deletions
diff --git a/vmime/net/folder.hpp b/vmime/net/folder.hpp index b34ff812..f65f3711 100644 --- a/vmime/net/folder.hpp +++ b/vmime/net/folder.hpp @@ -39,6 +39,7 @@ #include "vmime/message.hpp" #include "vmime/net/message.hpp" #include "vmime/net/events.hpp" +#include "vmime/net/folderStatus.hpp" #include "vmime/utility/path.hpp" #include "vmime/utility/stream.hpp" @@ -335,12 +336,21 @@ public: /** 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 net_exception if an error occurs */ virtual void status(int& count, int& unseen) = 0; + /** Request folder status without opening it. + * + * @return current folder status + * @throw net_exception if an error occurs + */ + virtual ref <folderStatus> getStatus() = 0; + /** Expunge deleted messages. * * @throw net_exception if an error occurs diff --git a/vmime/net/folderStatus.hpp b/vmime/net/folderStatus.hpp new file mode 100644 index 00000000..90beea66 --- /dev/null +++ b/vmime/net/folderStatus.hpp @@ -0,0 +1,68 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// 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 unsigned int getMessageCount() const = 0; + + /** Returns the number of unseen messages in the folder. + * + * @return number of unseen messages + */ + virtual unsigned int getUnseenCount() const = 0; +}; + + +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES + +#endif // VMIME_NET_FOLDERSTATUS_HPP_INCLUDED diff --git a/vmime/net/imap/IMAPConnection.hpp b/vmime/net/imap/IMAPConnection.hpp index 257e60d3..72defc29 100644 --- a/vmime/net/imap/IMAPConnection.hpp +++ b/vmime/net/imap/IMAPConnection.hpp @@ -96,6 +96,7 @@ public: void fetchCapabilities(); void invalidateCapabilities(); const std::vector <string> getCapabilities(); + bool hasCapability(const string& capa); ref <security::authenticator> getAuthenticator(); @@ -104,6 +105,9 @@ public: ref <const socket> getSocket() const; + bool isMODSEQDisabled() const; + void disableMODSEQ(); + private: void authenticate(); @@ -115,6 +119,9 @@ private: void startTLS(); #endif // VMIME_HAVE_TLS_SUPPORT + bool processCapabilityResponseData(const IMAPParser::response* resp); + void processCapabilityResponseData(const IMAPParser::capability_data* capaData); + weak_ref <IMAPStore> m_store; @@ -140,6 +147,8 @@ private: std::vector <string> m_capabilities; bool m_capabilitiesFetched; + bool m_noModSeq; + void internalDisconnect(); diff --git a/vmime/net/imap/IMAPFolder.hpp b/vmime/net/imap/IMAPFolder.hpp index 55c16e9c..48e07603 100644 --- a/vmime/net/imap/IMAPFolder.hpp +++ b/vmime/net/imap/IMAPFolder.hpp @@ -38,6 +38,8 @@ #include "vmime/net/folder.hpp" +#include "vmime/net/imap/IMAPParser.hpp" + namespace vmime { namespace net { @@ -47,6 +49,7 @@ namespace imap { class IMAPStore; class IMAPMessage; class IMAPConnection; +class IMAPFolderStatus; /** IMAP folder implementation. @@ -62,7 +65,7 @@ private: IMAPFolder(const folder::path& path, ref <IMAPStore> store, const int type = TYPE_UNDEFINED, const int flags = FLAG_UNDEFINED); - IMAPFolder(const IMAPFolder&) : folder() { } + IMAPFolder(const IMAPFolder&); ~IMAPFolder(); @@ -118,6 +121,9 @@ public: void copyMessages(const folder::path& dest, const std::vector <int>& nums); void status(int& count, int& unseen); + ref <folderStatus> getStatus(); + + void noop(); void expunge(); @@ -148,6 +154,18 @@ private: void copyMessages(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_ref <IMAPStore> m_store; ref <IMAPConnection> m_connection; @@ -161,8 +179,8 @@ private: int m_flags; int m_messageCount; - - unsigned int m_uidValidity; + vmime_uint32 m_uidValidity; + ref <IMAPFolderStatus> m_status; std::vector <IMAPMessage*> m_messages; }; diff --git a/vmime/net/imap/IMAPFolderStatus.hpp b/vmime/net/imap/IMAPFolderStatus.hpp new file mode 100644 index 00000000..1cad217c --- /dev/null +++ b/vmime/net/imap/IMAPFolderStatus.hpp @@ -0,0 +1,117 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// 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: + + // Inherited from folderStatus + unsigned int getMessageCount() const; + unsigned int getUnseenCount() const; + + /** Returns the the number of messages with the Recent flag set. + * + * @return number of messages flagged Recent + */ + unsigned int 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 + */ + void updateFromResponse(const IMAPParser::mailbox_data* resp); + + /** Reads the folder status from the specified IMAP response. + * + * @param resp parsed IMAP response + */ + void updateFromResponse(const IMAPParser::resp_text_code* resp); + +private: + + unsigned int m_count; + unsigned int m_unseen; + unsigned int 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/net/imap/IMAPMessage.hpp b/vmime/net/imap/IMAPMessage.hpp index 5c36ce13..fb86696f 100644 --- a/vmime/net/imap/IMAPMessage.hpp +++ b/vmime/net/imap/IMAPMessage.hpp @@ -57,7 +57,7 @@ private: friend class vmime::creator; // vmime::create <IMAPMessage> IMAPMessage(ref <IMAPFolder> folder, const int num); - IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uniqueId); + IMAPMessage(ref <IMAPFolder> folder, const int num, const uid& uid); IMAPMessage(const IMAPMessage&) : message() { } ~IMAPMessage(); @@ -66,7 +66,19 @@ public: int getNumber() const; - const uid getUniqueId() 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; int getSize() const; @@ -89,8 +101,6 @@ public: private: - void fetch(ref <IMAPFolder> folder, const int options); - void processFetchResponse(const int options, const IMAPParser::message_data* msgData); /** Recursively fetch part header for all parts in the structure. @@ -132,6 +142,7 @@ private: int m_flags; bool m_expunged; uid m_uid; + vmime_uint64 m_modseq; ref <header> m_header; ref <structure> m_structure; diff --git a/vmime/net/imap/IMAPParser.hpp b/vmime/net/imap/IMAPParser.hpp index 41252a92..af871c27 100644 --- a/vmime/net/imap/IMAPParser.hpp +++ b/vmime/net/imap/IMAPParser.hpp @@ -1288,6 +1288,211 @@ public: }; + // seq-number = nz-number / "*" + // ; message sequence number (COPY, FETCH, STORE + // ; commands) or unique identifier (UID COPY, + // ; UID FETCH, UID STORE commands). + + class seq_number : public component + { + public: + + seq_number() + : m_number(NULL), m_star(false) + { + } + + ~seq_number() + { + delete m_number; + } + + void go(IMAPParser& parser, string& line, string::size_type* currentPos) + { + DEBUG_ENTER_COMPONENT("seq_number"); + + string::size_type pos = *currentPos; + + if (parser.check <one_char <'*'> >(line, &pos, true)) + { + m_star = true; + m_number = NULL; + } + else + { + m_star = false; + m_number = parser.get <IMAPParser::number>(line, &pos); + } + + *currentPos = pos; + } + + private: + + IMAPParser::number* m_number; + bool m_star; + + public: + + const IMAPParser::number* number() const { return m_number; } + bool star() const { return m_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. + + class seq_range : public component + { + public: + + seq_range() + : m_first(NULL), m_last(NULL) + { + } + + ~seq_range() + { + delete m_first; + delete m_last; + } + + void go(IMAPParser& parser, string& line, string::size_type* currentPos) + { + DEBUG_ENTER_COMPONENT("seq_range"); + + string::size_type pos = *currentPos; + + m_first = parser.get <seq_number>(line, &pos); + + parser.check <one_char <'*'> >(line, &pos); + + m_last = parser.get <seq_number>(line, &pos); + + *currentPos = pos; + } + + private: + + IMAPParser::seq_number* m_first; + IMAPParser::seq_number* m_last; + + public: + + const IMAPParser::seq_number* first() const { return m_first; } + const IMAPParser::seq_number* last() const { return m_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 + + class sequence_set : public component + { + public: + + sequence_set() + : m_number(NULL), m_range(NULL), m_nextSet(NULL) + { + } + + ~sequence_set() + { + delete m_number; + delete m_range; + delete m_nextSet; + } + + void go(IMAPParser& parser, string& line, string::size_type* currentPos) + { + DEBUG_ENTER_COMPONENT("sequence_set"); + + string::size_type pos = *currentPos; + + if ((m_range = parser.get <IMAPParser::seq_range>(line, &pos, true)) == NULL) + m_number = parser.get <IMAPParser::seq_number>(line, &pos); + + if (parser.check <one_char <','> >(line, &pos, true)) + m_nextSet = parser.get <sequence_set>(line, &pos); + + *currentPos = pos; + } + + private: + + IMAPParser::seq_number* m_number; + IMAPParser::seq_range* m_range; + IMAPParser::sequence_set* m_nextSet; + + public: + + const IMAPParser::seq_number* seq_number() const { return m_number; } + const IMAPParser::seq_range* seq_range() const { return m_range; } + const IMAPParser::sequence_set* next_sequence_set() const { return m_nextSet; } + }; + + + // mod-sequence-value = 1*DIGIT + // ;; Positive unsigned 64-bit integer + // ;; (mod-sequence) + // ;; (1 <= n < 18,446,744,073,709,551,615) + + class mod_sequence_value : public component + { + public: + + mod_sequence_value() + : m_value(0) + { + } + + void go(IMAPParser& /* parser */, string& line, string::size_type* currentPos) + { + DEBUG_ENTER_COMPONENT("mod_sequence_value"); + + string::size_type 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; + } + } + + m_value = val; + + *currentPos = pos; + } + + private: + + vmime_uint64 m_value; + + public: + + const vmime_uint64 value() const { return m_value; } + }; + + // // flag ::= "\Answered" / "\Flagged" / "\Deleted" / // "\Seen" / "\Draft" / flag_keyword / flag_extension @@ -1666,249 +1871,6 @@ public: // - // resp_text_code ::= "ALERT" / "PARSE" / - // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" / - // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / - // "UIDVALIDITY" SPACE nz_number / - // "UNSEEN" SPACE nz_number / - // atom [SPACE 1*<any TEXT_CHAR except "]">] - - class resp_text_code : public component - { - public: - - resp_text_code() - : m_nz_number(NULL), m_atom(NULL), m_flag_list(NULL), m_text(NULL) - { - } - - ~resp_text_code() - { - delete (m_nz_number); - delete (m_atom); - delete (m_flag_list); - delete (m_text); - } - - void go(IMAPParser& parser, string& line, string::size_type* currentPos) - { - DEBUG_ENTER_COMPONENT("resp_text_code"); - - string::size_type pos = *currentPos; - - // "ALERT" - if (parser.checkWithArg <special_atom>(line, &pos, "alert", true)) - { - m_type = ALERT; - } - // "PARSE" - else if (parser.checkWithArg <special_atom>(line, &pos, "parse", true)) - { - m_type = PARSE; - } - // "PERMANENTFLAGS" SPACE flag_list - else if (parser.checkWithArg <special_atom>(line, &pos, "permanentflags", true)) - { - m_type = PERMANENTFLAGS; - - parser.check <SPACE>(line, &pos); - - m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos); - } - // "READ-ONLY" - else if (parser.checkWithArg <special_atom>(line, &pos, "read-only", true)) - { - m_type = READ_ONLY; - } - // "READ-WRITE" - else if (parser.checkWithArg <special_atom>(line, &pos, "read-write", true)) - { - m_type = READ_WRITE; - } - // "TRYCREATE" - else if (parser.checkWithArg <special_atom>(line, &pos, "trycreate", true)) - { - m_type = TRYCREATE; - } - // "UIDVALIDITY" SPACE nz_number - else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true)) - { - m_type = UIDVALIDITY; - - parser.check <SPACE>(line, &pos); - m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos); - } - // "UNSEEN" SPACE nz_number - else if (parser.checkWithArg <special_atom>(line, &pos, "unseen", true)) - { - m_type = UNSEEN; - - parser.check <SPACE>(line, &pos); - m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos); - } - // atom [SPACE 1*<any TEXT_CHAR except "]">] - else - { - m_type = OTHER; - - m_atom = parser.get <IMAPParser::atom>(line, &pos); - - if (parser.check <SPACE>(line, &pos, true)) - m_text = parser.get <text_except <']'> >(line, &pos); - } - - *currentPos = pos; - } - - - enum Type - { - ALERT, - PARSE, - PERMANENTFLAGS, - READ_ONLY, - READ_WRITE, - TRYCREATE, - UIDVALIDITY, - UNSEEN, - OTHER - }; - - private: - - Type m_type; - - IMAPParser::nz_number* m_nz_number; - IMAPParser::atom* m_atom; - IMAPParser::flag_list* m_flag_list; - IMAPParser::text* m_text; - - public: - - Type type() const { return (m_type); } - - const IMAPParser::nz_number* nz_number() const { return (m_nz_number); } - const IMAPParser::atom* atom() const { return (m_atom); } - const IMAPParser::flag_list* flag_list() const { return (m_flag_list); } - const IMAPParser::text* text() const { return (m_text); } - }; - - - // - // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text) - // ;; text SHOULD NOT begin with "[" or "=" - - class resp_text : public component - { - public: - - resp_text() - : m_resp_text_code(NULL) - { - } - - ~resp_text() - { - delete (m_resp_text_code); - } - - void go(IMAPParser& parser, string& line, string::size_type* currentPos) - { - DEBUG_ENTER_COMPONENT("resp_text"); - - string::size_type pos = *currentPos; - - if (parser.check <one_char <'['> >(line, &pos, true)) - { - m_resp_text_code = parser.get <IMAPParser::resp_text_code>(line, &pos); - - parser.check <one_char <']'> >(line, &pos); - parser.check <SPACE>(line, &pos, true); - } - - text_mime2* text1 = parser.get <text_mime2>(line, &pos, true); - - if (text1 != NULL) - { - m_text = text1->value(); - delete (text1); - } - else - { - IMAPParser::text* text2 = - parser.get <IMAPParser::text>(line, &pos, true); - - if (text2 != NULL) - { - m_text = text2->value(); - delete (text2); - } - else - { - // Empty response text - } - } - - *currentPos = pos; - } - - private: - - IMAPParser::resp_text_code* m_resp_text_code; - string m_text; - - public: - - const IMAPParser::resp_text_code* resp_text_code() const { return (m_resp_text_code); } - const string& text() const { return (m_text); } - }; - - - // - // continue_req ::= "+" SPACE (resp_text / base64) - // - - class continue_req : public component - { - public: - - continue_req() - : m_resp_text(NULL) - { - } - - ~continue_req() - { - delete (m_resp_text); - } - - void go(IMAPParser& parser, string& line, string::size_type* currentPos) - { - DEBUG_ENTER_COMPONENT("continue_req"); - - string::size_type pos = *currentPos; - - parser.check <one_char <'+'> >(line, &pos); - parser.check <SPACE>(line, &pos); - - m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos); - - parser.check <CRLF>(line, &pos); - - *currentPos = pos; - } - - private: - - IMAPParser::resp_text* m_resp_text; - - public: - - const IMAPParser::resp_text* resp_text() const { return (m_resp_text); } - }; - - - // // auth_type ::= atom // ;; Defined by [IMAP-AUTH] // @@ -1965,6 +1927,13 @@ public: // ("UIDVALIDITY" SP nz-number) / // ("UNSEEN" SP number) // + // IMAP Extension for Conditional STORE (RFC-4551): + // + // status-att-val =/ "HIGHESTMODSEQ" SP mod-sequence-valzer + // ;; extends non-terminal defined in [IMAPABNF]. + // ;; Value 0 denotes that the mailbox doesn't + // ;; support persistent mod-sequences + // class status_att_val : public component { @@ -1976,30 +1945,41 @@ public: string::size_type pos = *currentPos; - if (parser.checkWithArg <special_atom>(line, &pos, "messages", true)) - { - m_type = MESSAGES; - } - else if (parser.checkWithArg <special_atom>(line, &pos, "recent", true)) - { - m_type = RECENT; - } - else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true)) - { - m_type = UIDNEXT; - } - else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true)) + // "HIGHESTMODSEQ" SP mod-sequence-valzer + if (parser.checkWithArg <special_atom>(line, &pos, "highestmodseq", true)) { - m_type = UIDVALIDITY; + m_type = HIGHESTMODSEQ; + + parser.check <SPACE>(line, &pos); + m_value = parser.get <IMAPParser::mod_sequence_value>(line, &pos); } else { - parser.checkWithArg <special_atom>(line, &pos, "unseen"); - m_type = UNSEEN; - } + if (parser.checkWithArg <special_atom>(line, &pos, "messages", true)) + { + m_type = MESSAGES; + } + else if (parser.checkWithArg <special_atom>(line, &pos, "recent", true)) + { + m_type = RECENT; + } + else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true)) + { + m_type = UIDNEXT; + } + else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true)) + { + m_type = UIDVALIDITY; + } + else + { + parser.checkWithArg <special_atom>(line, &pos, "unseen"); + m_type = UNSEEN; + } - parser.check <SPACE>(line, &pos); - m_value = parser.get <IMAPParser::number>(line, &pos); + parser.check <SPACE>(line, &pos); + m_value = parser.get <IMAPParser::number>(line, &pos); + } *currentPos = pos; } @@ -2007,6 +1987,10 @@ public: enum Type { + // Extensions + HIGHESTMODSEQ, + + // Standard IMAP MESSAGES, RECENT, UIDNEXT, @@ -2027,6 +2011,11 @@ public: { return dynamic_cast <IMAPParser::number *>(m_value); } + + const IMAPParser::mod_sequence_value* value_as_mod_sequence_value() const + { + return dynamic_cast <IMAPParser::mod_sequence_value *>(m_value); + } }; @@ -3882,6 +3871,9 @@ public: // "BODY" section ["<" number ">"] SPACE nstring / // "UID" SPACE uniqueid // + // IMAP Extension for Conditional STORE (RFC-4551): + // + // msg_att_item /= "MODSEQ" SP "(" mod_sequence_value ")" class msg_att_item : public component { @@ -3890,7 +3882,7 @@ public: msg_att_item() : m_date_time(NULL), m_number(NULL), m_envelope(NULL), m_uniqueid(NULL), m_nstring(NULL), m_body(NULL), m_flag_list(NULL), - m_section(NULL) + m_section(NULL), m_mod_sequence_value(NULL) { } @@ -3905,6 +3897,7 @@ public: delete (m_body); delete (m_flag_list); delete (m_section); + delete m_mod_sequence_value; } void go(IMAPParser& parser, string& line, string::size_type* currentPos) @@ -4015,6 +4008,18 @@ public: m_body = parser.get <IMAPParser::body>(line, &pos); } } + // "MODSEQ" SP "(" mod_sequence_value ")" + else if (parser.checkWithArg <special_atom>(line, &pos, "modseq", true)) + { + m_type = MODSEQ; + + parser.check <SPACE>(line, &pos); + parser.check <one_char <'('> >(line, &pos); + + m_mod_sequence_value = parser.get <IMAPParser::mod_sequence_value>(line, &pos); + + parser.check <one_char <')'> >(line, &pos); + } // "UID" SPACE uniqueid else { @@ -4042,7 +4047,8 @@ public: BODY, BODY_SECTION, BODY_STRUCTURE, - UID + UID, + MODSEQ }; private: @@ -4057,6 +4063,7 @@ public: IMAPParser::xbody* m_body; IMAPParser::flag_list* m_flag_list; IMAPParser::section* m_section; + IMAPParser::mod_sequence_value* m_mod_sequence_value; public: @@ -4070,6 +4077,7 @@ public: const IMAPParser::xbody* body() const { return (m_body); } const IMAPParser::flag_list* flag_list() const { return (m_flag_list); } const IMAPParser::section* section() const { return (m_section); } + const IMAPParser::mod_sequence_value* mod_sequence_value() { return m_mod_sequence_value; } }; @@ -4189,6 +4197,307 @@ public: // + // resp_text_code ::= "ALERT" / "PARSE" / + // capability-data / + // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" / + // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" / + // "UIDVALIDITY" SPACE nz_number / + // "UNSEEN" SPACE nz_number / + // atom [SPACE 1*<any TEXT_CHAR except "]">] + // + // IMAP Extension for Conditional STORE (RFC-4551): + // + // resp-text-code =/ "HIGHESTMODSEQ" SP mod-sequence-value / + // "NOMODSEQ" / + // "MODIFIED" SP set + + class resp_text_code : public component + { + public: + + resp_text_code() + : m_nz_number(NULL), m_atom(NULL), m_flag_list(NULL), + m_text(NULL), m_capability_data(NULL) + { + } + + ~resp_text_code() + { + delete (m_nz_number); + delete (m_atom); + delete (m_flag_list); + delete (m_text); + delete m_capability_data; + } + + void go(IMAPParser& parser, string& line, string::size_type* currentPos) + { + DEBUG_ENTER_COMPONENT("resp_text_code"); + + string::size_type pos = *currentPos; + + // "ALERT" + if (parser.checkWithArg <special_atom>(line, &pos, "alert", true)) + { + m_type = ALERT; + } + // "PARSE" + else if (parser.checkWithArg <special_atom>(line, &pos, "parse", true)) + { + m_type = PARSE; + } + // capability_data + else if ((m_capability_data = parser.get <IMAPParser::capability_data>(line, &pos, true))) + { + m_type = CAPABILITY; + } + // "PERMANENTFLAGS" SPACE flag_list + else if (parser.checkWithArg <special_atom>(line, &pos, "permanentflags", true)) + { + m_type = PERMANENTFLAGS; + + parser.check <SPACE>(line, &pos); + + m_flag_list = parser.get <IMAPParser::flag_list>(line, &pos); + } + // "READ-ONLY" + else if (parser.checkWithArg <special_atom>(line, &pos, "read-only", true)) + { + m_type = READ_ONLY; + } + // "READ-WRITE" + else if (parser.checkWithArg <special_atom>(line, &pos, "read-write", true)) + { + m_type = READ_WRITE; + } + // "TRYCREATE" + else if (parser.checkWithArg <special_atom>(line, &pos, "trycreate", true)) + { + m_type = TRYCREATE; + } + // "UIDVALIDITY" SPACE nz_number + else if (parser.checkWithArg <special_atom>(line, &pos, "uidvalidity", true)) + { + m_type = UIDVALIDITY; + + parser.check <SPACE>(line, &pos); + m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos); + } + // "UIDNEXT" SPACE nz_number + else if (parser.checkWithArg <special_atom>(line, &pos, "uidnext", true)) + { + m_type = UIDNEXT; + + parser.check <SPACE>(line, &pos); + m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos); + } + // "UNSEEN" SPACE nz_number + else if (parser.checkWithArg <special_atom>(line, &pos, "unseen", true)) + { + m_type = UNSEEN; + + parser.check <SPACE>(line, &pos); + m_nz_number = parser.get <IMAPParser::nz_number>(line, &pos); + } + // "HIGHESTMODSEQ" SP mod-sequence-value + else if (parser.checkWithArg <special_atom>(line, &pos, "highestmodseq", true)) + { + m_type = HIGHESTMODSEQ; + + parser.check <SPACE>(line, &pos); + m_mod_sequence_value = parser.get <IMAPParser::mod_sequence_value>(line, &pos); + } + // "NOMODSEQ" + else if (parser.checkWithArg <special_atom>(line, &pos, "nomodseq", true)) + { + m_type = NOMODSEQ; + } + // "MODIFIED" SP sequence-set + else if (parser.checkWithArg <special_atom>(line, &pos, "modified", true)) + { + m_type = MODIFIED; + + parser.check <SPACE>(line, &pos); + + m_sequence_set = parser.get <IMAPParser::sequence_set>(line, &pos); + } + // atom [SPACE 1*<any TEXT_CHAR except "]">] + else + { + m_type = OTHER; + + m_atom = parser.get <IMAPParser::atom>(line, &pos); + + if (parser.check <SPACE>(line, &pos, true)) + m_text = parser.get <text_except <']'> >(line, &pos); + } + + *currentPos = pos; + } + + + enum Type + { + // Extensions + HIGHESTMODSEQ, + NOMODSEQ, + MODIFIED, + + // Standard IMAP + ALERT, + PARSE, + CAPABILITY, + PERMANENTFLAGS, + READ_ONLY, + READ_WRITE, + TRYCREATE, + UIDVALIDITY, + UIDNEXT, + UNSEEN, + OTHER + }; + + private: + + Type m_type; + + IMAPParser::nz_number* m_nz_number; + IMAPParser::atom* m_atom; + IMAPParser::flag_list* m_flag_list; + IMAPParser::text* m_text; + IMAPParser::mod_sequence_value* m_mod_sequence_value; + IMAPParser::sequence_set* m_sequence_set; + IMAPParser::capability_data* m_capability_data; + + public: + + Type type() const { return (m_type); } + + const IMAPParser::nz_number* nz_number() const { return (m_nz_number); } + const IMAPParser::atom* atom() const { return (m_atom); } + const IMAPParser::flag_list* flag_list() const { return (m_flag_list); } + const IMAPParser::text* text() const { return (m_text); } + const IMAPParser::mod_sequence_value* mod_sequence_value() const { return m_mod_sequence_value; } + const IMAPParser::sequence_set* sequence_set() const { return m_sequence_set; } + const IMAPParser::capability_data* capability_data() const { return m_capability_data; } + }; + + + // + // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text) + // ;; text SHOULD NOT begin with "[" or "=" + + class resp_text : public component + { + public: + + resp_text() + : m_resp_text_code(NULL) + { + } + + ~resp_text() + { + delete (m_resp_text_code); + } + + void go(IMAPParser& parser, string& line, string::size_type* currentPos) + { + DEBUG_ENTER_COMPONENT("resp_text"); + + string::size_type pos = *currentPos; + + if (parser.check <one_char <'['> >(line, &pos, true)) + { + m_resp_text_code = parser.get <IMAPParser::resp_text_code>(line, &pos); + + parser.check <one_char <']'> >(line, &pos); + parser.check <SPACE>(line, &pos, true); + } + + text_mime2* text1 = parser.get <text_mime2>(line, &pos, true); + + if (text1 != NULL) + { + m_text = text1->value(); + delete (text1); + } + else + { + IMAPParser::text* text2 = + parser.get <IMAPParser::text>(line, &pos, true); + + if (text2 != NULL) + { + m_text = text2->value(); + delete (text2); + } + else + { + // Empty response text + } + } + + *currentPos = pos; + } + + private: + + IMAPParser::resp_text_code* m_resp_text_code; + string m_text; + + public: + + const IMAPParser::resp_text_code* resp_text_code() const { return (m_resp_text_code); } + const string& text() const { return (m_text); } + }; + + + // + // continue_req ::= "+" SPACE (resp_text / base64) + // + + class continue_req : public component + { + public: + + continue_req() + : m_resp_text(NULL) + { + } + + ~continue_req() + { + delete (m_resp_text); + } + + void go(IMAPParser& parser, string& line, string::size_type* currentPos) + { + DEBUG_ENTER_COMPONENT("continue_req"); + + string::size_type pos = *currentPos; + + parser.check <one_char <'+'> >(line, &pos); + parser.check <SPACE>(line, &pos); + + m_resp_text = parser.get <IMAPParser::resp_text>(line, &pos); + + parser.check <CRLF>(line, &pos); + + *currentPos = pos; + } + + private: + + IMAPParser::resp_text* m_resp_text; + + public: + + const IMAPParser::resp_text* resp_text() const { return (m_resp_text); } + }; + + + // // resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text // ;; Status condition // diff --git a/vmime/net/imap/IMAPStore.hpp b/vmime/net/imap/IMAPStore.hpp index 6a06fdc9..e6b27d8d 100644 --- a/vmime/net/imap/IMAPStore.hpp +++ b/vmime/net/imap/IMAPStore.hpp @@ -86,6 +86,7 @@ public: bool isSecuredConnection() const; ref <connectionInfos> getConnectionInfos() const; + ref <IMAPConnection> getConnection(); protected: diff --git a/vmime/net/imap/IMAPUtils.hpp b/vmime/net/imap/IMAPUtils.hpp index aea02ef9..591db3f3 100644 --- a/vmime/net/imap/IMAPUtils.hpp +++ b/vmime/net/imap/IMAPUtils.hpp @@ -37,6 +37,7 @@ #include "vmime/net/folder.hpp" #include "vmime/net/message.hpp" #include "vmime/net/imap/IMAPParser.hpp" +#include "vmime/net/imap/IMAPConnection.hpp" #include "vmime/mailboxList.hpp" @@ -104,19 +105,23 @@ public: /** Construct a fetch request for the specified messages, designated by their sequence numbers. * + * @param cnt connection * @param list list of message numbers * @param options fetch options * @return fetch request */ - static const string buildFetchRequest(const std::vector <int>& list, const int options); + static const string buildFetchRequest + (ref <IMAPConnection> cnt, const std::vector <int>& list, const int options); /** Construct a fetch request for the specified messages, designated by their UIDs. * + * @param cnt connection * @param list list of message UIDs * @param options fetch options * @return fetch request */ - static const string buildFetchRequest(const std::vector <message::uid>& list, const int options); + static const string buildFetchRequest + (ref <IMAPConnection> cnt, const std::vector <message::uid>& list, const int options); /** Convert a parser-style address list to a mailbox list. * @@ -130,7 +135,7 @@ public: * @param uid globally unique UID (as returned by makeGlobalUID(), for example) * @return message UID */ - static unsigned int extractUIDFromGlobalUID(const message::uid& uid); + static vmime_uint32 extractUIDFromGlobalUID(const message::uid& uid); /** Construct a globally unique UID from UID Validity and a message UID. * @@ -138,12 +143,12 @@ public: * @param messageUID UID of the message * @return global UID */ - static const message::uid makeGlobalUID(const unsigned int UIDValidity, const unsigned int messageUID); + static const message::uid makeGlobalUID(const vmime_uint32 UIDValidity, const vmime_uint32 messageUID); private: static const string buildFetchRequestImpl - (const string& mode, const string& set, const int options); + (ref <IMAPConnection> cnt, const string& mode, const string& set, const int options); }; diff --git a/vmime/net/maildir/maildirFolder.hpp b/vmime/net/maildir/maildirFolder.hpp index 8a418268..940fcaae 100644 --- a/vmime/net/maildir/maildirFolder.hpp +++ b/vmime/net/maildir/maildirFolder.hpp @@ -117,6 +117,7 @@ public: void copyMessages(const folder::path& dest, const std::vector <int>& nums); void status(int& count, int& unseen); + ref <folderStatus> getStatus(); void expunge(); diff --git a/vmime/net/maildir/maildirFolderStatus.hpp b/vmime/net/maildir/maildirFolderStatus.hpp new file mode 100644 index 00000000..80018b14 --- /dev/null +++ b/vmime/net/maildir/maildirFolderStatus.hpp @@ -0,0 +1,70 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED +#define VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + + +#include "vmime/net/folderStatus.hpp" + + +namespace vmime { +namespace net { +namespace maildir { + + +/** Holds the status of a Maildir folder. + */ + +class VMIME_EXPORT maildirFolderStatus : public folderStatus +{ +public: + + // Inherited from folderStatus + unsigned int getMessageCount() const; + unsigned int getUnseenCount() const; + + void setMessageCount(const unsigned int count); + void setUnseenCount(const unsigned int unseen); + +private: + + unsigned int m_count; + unsigned int m_unseen; +}; + + +} // maildir +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR + +#endif // VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED diff --git a/vmime/net/maildir/maildirMessage.hpp b/vmime/net/maildir/maildirMessage.hpp index 4efc2eed..de8c1751 100644 --- a/vmime/net/maildir/maildirMessage.hpp +++ b/vmime/net/maildir/maildirMessage.hpp @@ -62,7 +62,7 @@ public: int getNumber() const; - const uid getUniqueId() const; + const uid getUID() const; int getSize() const; diff --git a/vmime/net/message.hpp b/vmime/net/message.hpp index 288e08a2..3b94fbf3 100644 --- a/vmime/net/message.hpp +++ b/vmime/net/message.hpp @@ -204,11 +204,12 @@ public: */ virtual int getNumber() const = 0; - /** Return the unique identified of this message (must fetch before). + /** Return the unique identifier (UID) of this message in its + * folder (must fetch before). * * @return UID of the message */ - virtual const uid getUniqueId() const = 0; + virtual const uid getUID() const = 0; /** Return the size of the message (must fetch before). * diff --git a/vmime/net/pop3/POP3Folder.hpp b/vmime/net/pop3/POP3Folder.hpp index 952b8580..8a97213c 100644 --- a/vmime/net/pop3/POP3Folder.hpp +++ b/vmime/net/pop3/POP3Folder.hpp @@ -114,6 +114,7 @@ public: void copyMessages(const folder::path& dest, const std::vector <int>& nums); void status(int& count, int& unseen); + ref <folderStatus> getStatus(); void expunge(); diff --git a/vmime/net/pop3/POP3FolderStatus.hpp b/vmime/net/pop3/POP3FolderStatus.hpp new file mode 100644 index 00000000..3e5d15a1 --- /dev/null +++ b/vmime/net/pop3/POP3FolderStatus.hpp @@ -0,0 +1,70 @@ +// +// VMime library (http://www.vmime.org) +// Copyright (C) 2002-2013 Vincent Richard <[email protected]> +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#ifndef VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED +#define VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED + + +#include "vmime/config.hpp" + + +#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3 + + +#include "vmime/net/folderStatus.hpp" + + +namespace vmime { +namespace net { +namespace pop3 { + + +/** Holds the status of a POP3 folder. + */ + +class VMIME_EXPORT POP3FolderStatus : public folderStatus +{ +public: + + // Inherited from folderStatus + unsigned int getMessageCount() const; + unsigned int getUnseenCount() const; + + void setMessageCount(const unsigned int count); + void setUnseenCount(const unsigned int unseen); + +private: + + unsigned int m_count; + unsigned int m_unseen; +}; + + +} // pop3 +} // net +} // vmime + + +#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3 + +#endif // VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED diff --git a/vmime/net/pop3/POP3Message.hpp b/vmime/net/pop3/POP3Message.hpp index c415e8a7..31b26154 100644 --- a/vmime/net/pop3/POP3Message.hpp +++ b/vmime/net/pop3/POP3Message.hpp @@ -62,7 +62,7 @@ public: int getNumber() const; - const uid getUniqueId() const; + const uid getUID() const; int getSize() const; |