#ifndef __MailFolder_h__ #define __MailFolder_h__ #include #include #include #include namespace mail { /// /// MailFolder is the IMAP mailbox index for one folder directory /// (Inbox, Spam, Trash, or any client-CREATEd folder). It does NOT /// change how mail is delivered - SMTPServer::inCreate() still just /// hardlinks/writes plain files straight into a folder directory, the /// same as before IMAP existed. What MailFolder adds, alongside those /// message files, is three small index files: /// /// .uidvalidity - generated once, read thereafter. /// .uidnext - monotonic counter, never reused even across /// EXPUNGE. /// .imapindex - one line per message: " /// " (last field /// may be empty). /// /// load() reconciles the index against an actual directory scan: any /// message file present on disk that isn't yet in the index (freshly /// delivered SMTP mail, most commonly) gets a UID assigned and is /// marked \Recent for this one load() only; any indexed file no /// longer present (expunged some other way) is dropped. This is the /// ONLY integration point with delivery - delivery code never needs /// to know a UID scheme exists. /// class MailFolder { public: struct Message { uint32_t uid = 0; std::string fileName; std::vector flags; bool recent = false; size_t size = 0; time_t internalDate = 0; }; bool load(std::string folderPath); void save(); uint32_t uidValidity() const { return mUidValidity; } uint32_t uidNext() const { return mUidNext; } size_t size() const { return mMessages.size(); } const std::vector &messages() const { return mMessages; } // 1-based sequence number <-> UID (ascending UID order defines // sequence order). Returns 0 for "not present"/"out of range". uint32_t seq(uint32_t uid) const; uint32_t uidForSeq(uint32_t seqNum) const; Message *find(uint32_t uid); size_t recentCount() const; size_t unseenCount() const; uint32_t firstUnseenSeq() const; std::string readMessage(uint32_t uid); void setFlags(uint32_t uid, const std::vector &flags); void addFlags(uint32_t uid, const std::vector &flags); void removeFlags(uint32_t uid, const std::vector &flags); // internalDate == 0 means "use now". Not marked \Recent - an // APPEND/COPY destination message is never \Recent (RFC 3501 // 2.3.2: \Recent means "delivered since the last time any session // selected this mailbox", which by definition isn't true of a // message THIS session just created). uint32_t append(const std::string &data, const std::vector &flags, time_t internalDate = 0); // Unlinks every \Deleted message and removes it from the index. // Returns the sequence numbers to report via "* n EXPUNGE", each // ALREADY ADJUSTED for the responses sent before it (see // __IMAP_EXPUNGE.cpp's doc comment for why that adjustment is // required, not optional). std::vector expunge(); // Unlinks one specific message and removes it from the index - // POP3's QUIT (RFC 1939 6) needs this instead of expunge(): POP3 // deletion marks are tracked by POP3Session as a set of message // numbers, entirely separate from the \Deleted flag expunge() // acts on, since POP3 has no flags at all. void deleteMessage(uint32_t uid); std::string path; private: uint32_t mUidValidity = 0; uint32_t mUidNext = 1; std::vector mMessages; void loadIndexFile(); void reconcileWithDisk(); static std::string generateFileName(); }; } #endif