/* ** Copyright 2003-2008, Double Precision Inc. ** ** See COPYING for distribution information. */ #ifndef libmail_mail_H #define libmail_mail_H #include "libmail_config.h" #include #include #if HAVE_SYS_SELECT_H #include #endif #include #if TIME_WITH_SYS_TIME # include # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if HAVE_UNISTD_H #include #endif #include #include #include #include #include "namespace.H" #include "objectmonitor.H" #include "misc.H" #if LIBMAIL_THROW_DEBUG #define LIBMAIL_THROW(x) do { fprintf(stderr, "Exception at %s(%d)\n", __FILE__, __LINE__); throw x;} while (0) #else #define LIBMAIL_THROW(x) throw x #define LIBMAIL_THROW_EMPTY #endif LIBMAIL_START class envelope; class xenvelope; class mimestruct; class addMessage; class searchParams; class searchCallback; class smtpInfo; class snapshot; class loginInfo; // Encapsulate poll() structures typedef struct ::pollfd pollfd; // i.e. pollfd.fd, pollfd.events, static const int pollin=POLLIN; static const int pollpri=POLLPRI; static const int pollout=POLLOUT; static const int pollerr=POLLERR; static const int pollhup=POLLHUP; static const int pollread= POLLIN | POLLHUP | POLLERR; static const int pollwrite= POLLOUT | POLLERR; // // libmail.a uses a mail::callback object to notify the application when // the requested operation succeeds. libmail.a's API is completely // asynchronous. Most operations cannot be completed immediately. Instead, // the application passes a mail::callback object (or one of its subclasses) // to a function/method call that makes a particular request. The function // or a method returns immediately, and the mail::callback's success() or // fail() method will be called whenever the requested operation completes. // All processing occurs within mail::account::process(). // // It's possible that the requested operation can be completed immediately, // without blocking for I/O. In which case the function/method call invokes // the success() or the fail() method prior to returning. class callback { public: callback() {} virtual ~callback() {} virtual void success(std::string message)=0; virtual void fail(std::string message)=0; virtual void reportProgress(size_t bytesCompleted, size_t bytesEstimatedTotal, size_t messagesCompleted, size_t messagesEstimatedTotal)=0; class disconnect; class folder; class folderInfo; class folderList; class message; }; class folder; class messageInfo; class loginCallback; #define MAILCHECKINTERVAL 10 /////////////////////////////////////////////////////////////////////////// // // A mail::account object represents a single mail account. A mail account is // defined as a collection of related mail folders. A mail folder may // contain other mail subfolders, or messages (or both), depending on the // mail account. // // A mail::account object is not instantiated directly, but is instantiated by the // mail::account::open() function, which instantiated the appropriate subclass // based on the mail account's URL. mail::account::open() returns a new mail::account // object. As a rule, the mail::account object is not yet fully initialized; the // application must wait until the success() callback method is invoked. // // Mail folders are arranged into a tree-like hierarchy. The list of folders // at the topmost hierarchy level is obtained. by the readTopLevelFolders() // method. #define LIBMAIL_SINGLEFOLDER "*LIBMAIL_SINGLEFOLDER" #define LIBMAIL_CHEAPSTATUS "*LIBMAIL_CHEAPSTATUS" #define LIBMAIL_SERVERTYPE "*LIBMAIL_SERVERTYPE" #define LIBMAIL_SERVERDESCR "*LIBMAIL_SERVERDESCR" #define LIBMAIL_ACL "ACL" class account : public obj { // All instantiated mail::account objects: static std::list mailaccount_list; std::list::iterator my_mailaccount_p; virtual void resumed()=0; public: static void resume(); private: // Handle any pending I/O for this mail::account object. virtual void handler(std::vector &fds, int &timeout)=0; protected: // Disconnect callback object that's passed to the constructor. callback::disconnect &disconnect_callback; public: account(callback::disconnect &disconnect_callback); // // disconnect_callback - a callback object. // disconnect_callback.disconnected() gets called from within // handler() when the connection to the server is terminated. // disconnect_callback.servererror() gets called whenever the // server reports a fatal error which does not result in the // server connection shutting down. virtual ~account(); class openInfo { public: // // Information for creating a new mail::account object: std::string url; std::string pwd; std::vector certificates; // Raw SSL certificates std::string extraString; // newsrc filename, etc... mail::loginCallback *loginCallbackObj; openInfo(); ~openInfo(); }; static account *open(openInfo openInfoArg, callback &callback, callback::disconnect &disconnectCallback); // // Create a new mail::account object. // // url - mail account URL. // pwd - mail account password. May be an empty string for mail // accounts that do not require passwords (local mail storage). // callback - The open() function generally returns immediately. // The app must wait until callback.success() is invoked // indicating that libmail.a succesfully opened account. // callback.fail() is invoked if the login failed (at which // point the mail::account object is automatically destroyed). // A fatal error within the open function itself, // (such as an invalid URL or out of memory) results in // an invocation of callback.fail(), followed by open() // return a NULL pointer. // // disconnect_callback - // disconnect_callback.disconnected() gets called from // within handler() when the connection to the server is // terminated. disconnect_callback.servererror() gets // called whenever the server reports a fatal error which // does not result in the server connection shutting down. // // The disconnect_callback object may not be destroyed until // either callback.fail() calls, or the logout() function // completes (the fail() or the success() method of the // object passed to mail::account::logout() is invoked). static bool isRemoteUrl(std::string url); // Return TRUE if url represents a remote server account // (IMAP, POP3, NNTP, or SMTP) static void process(std::vector &fds, int &timeout); // // The process function is where ALL libmail.a processing takes // place. All other methods in all mail::account objects merely // initiate a request to perform the given task. The process() // function must be called periodically in order to process pending // I/O requests. // // The fds and timeout arguments are intended to be passed directly // to the poll(2) function call. Before calling process() initialize // fds to an empty vector. 'timeout' should also be initialized // to a fairly large timeout value, which should generally be the // timeout before any further application activity takes place. // // After process() terminates, it should not be invoked again until // poll(&fds[0], fds.size(), timeout) indicates that I/O requested // by the fd array is available, or until the 'tv' timeout expires. // // Note that the application should check if fds.size() == 0, which // indicates that libmail.a does not expect I/O on any file descriptor, // instead the application needs to wait for a simple timer to expire. // // If mail::account::process expects further processing to take place // earlier than what's indicated by 'timeout', mail::account::process() // will reduce the indicated timeout (the timeout will never be made // longer, only shorter). static int poll(std::vector &fds, int timeout); virtual void logout(callback &callback)=0; // // Close the mail account. The application should wait until // either callback.success() or callback.fail() is called (not much // of a difference, really, in both cases the mail::account object gets // automatically destroyed) virtual void checkNewMail(callback &callback)=0; // // Explicitly check for any new mail if a folder is currently open. // A call to mail::account::checkNewMail() invokes mail::folderCallback's // methods to reflect any changes to the currently open folder. // mail::folderCallback::newMessages() will be invoked if new messages // were added to the folder. mail::folderCallback::messagesRemoved() // will be invoked if messages were removed from a folder (perhaps // by another application doing updateFolderIndexInfo, and // mail::folderCallback::messageChanged() may be invoked to reflect // changes to existing messages. virtual bool hasCapability(std::string capability)=0; virtual std::string getCapability(std::string capability)=0; // // Indicate whether this mail::account object supports the indicated // capability. virtual class folder *folderFromString(std::string)=0; // // The opposite of mail::folder::toString(). Creates a new // mail::folder object. The mail::folder object is linked to this // mail::account object, and may only be used as argument to this mail::account // object's methods. // Note that the returned object does not imply that the actual // folder exists, only that if it does exist then the new // mail::folder object may be used to refer to it. virtual void readTopLevelFolders(callback::folderList &callback1, callback &callback2)=0; // Enumerate the topmost mail folders available in this mail account. // callback1.success() is invoked to enumerate the folders at the // top level of the folder hierarchy. virtual void findFolder(std::string path, callback::folderList &callback1, callback &callback2)=0; // Recreate a folder object. // // path - the folder's known path -- can be obtained by invoking // mail::folder::getPath(). // // name - the name of this folder, in the application charset. virtual std::string translatePath(std::string path)=0; // // Take a "human readable" path, and return its server representation. // For example: IMAP accounts translate path from the local charset // to modified-UTF7. // // Returns an empty string if the original path was invalid // (setting errno accordingly). A non-empty return does not guarantee // an existing folder, merely that the path is valid. virtual folder *getSendFolder(const smtpInfo &info, const mail::folder *folder, std::string &errmsg); // // Create a folder object to be used for sending outgoing // mail. // // info - parameters for sending mail // // folder - if not NULL, file a CC of the message into this folder // // errmsg - if this mail account login cannot be used for sending // mail, getSendFolder() returns a null ptr, and sets errmsg // accordingly. enum MessageAttributes { ARRIVALDATE=1, MESSAGESIZE=2, ENVELOPE=4, MIMESTRUCTURE=8}; virtual void readMessageAttributes(const std::vector &messages, MessageAttributes attributes, callback::message &callback)=0; // // Return metadata about messages in the currently open folder. // // messages - a list of messages whose metadata should be returned. // // attributes - which attributes to return. A logical OR of the // enumerated constant. Each constant directly translates to a // method in the mail::callback::message object. If multiple // messages are specified the order of messages for whom the // the attributes are returned is arbitrary. If multiple attrs // are specified the order in which the attributes are returned is // arbitrary. // With multiple messages and attributes, any order is possible. // It's possible that all attributes for the same message are // returned before the attributes for the next message are // returned; or the attribute for all messages are returned before // returning the next attribute for all messages, etc... // // ARRIVALDATE - when the message was added to the // folder (messageArrivalDateCallback). // // MESSAGESIZE - approximate message size (may not be // exact, may be just a rough estimate -- // messageSizeCallback). // // ENVELOPE - message envelope/thread summary // (messageEnvelopeCallback, maybe // messageReferencesCallback). // // MIMESTRUCTURE - message's MIME structure // (messageStructureCallback). // virtual void readMessageContent(const std::vector &messages, bool peek, enum mail::readMode readType, callback::message &callback)=0; // // Return the entire header and/or body content of one or more // messages. // // messages - a list of messages whose contents are returned. // peek - if true, do not reset the unread flag, if possible. // justHeader - return the contents of the header portion of the // message. // justContents - return the contents of the body portion of each // message. // mail::callback::message - the messageTextCallback method of // this object is invoked for each listed message. The relative // order of messages is arbitrary, but the requested contents of // each message are returned in their entirety before returning the // contents of the next message. // // Either justHeader or justContents (or both) must be set. If // only justHeader is set (justContents is not set), header lines are // automatically folded. virtual void readMessageContent(size_t messageNum, bool peek, const class mimestruct &msginfo, enum mail::readMode readType, callback::message &callback)=0; // // Return the contents of a MIME section of a message. // messageNum - the message whose contents are returned. // peek - do not reset the unread flag, if possible // msgInfo - the MIME section whose contents to be returned. // justHeader - return the contents of the header portion of the // message. // justContents - return the contents of the body portion of each // message. // // Either justHeader or justContents (or both) must be set. If // only justHeader is set (justContents is not set), header lines are // automatically folded. virtual void readMessageContentDecoded(size_t messageNum, bool peek, const class mimestruct &msginfo, callback::message &callback)=0; // // Return the decoded contents of a MIME section. Like // readMessageContents, except that base64/quoted-printable content // is automatically decoded, and callback.messageTextCallback() // gets the raw, decoded, contents. // // messageNum - the message whose contents are returned. // peek - do not reset the unread flag, if possible // msgInfo - the MIME section whose contents to be returned. virtual size_t getFolderIndexSize()=0; // // Return the number of messages in the currently opened folders. // The message number arguments to the previous functions should range // should range between 0 and one less than the return value from // getFolderIndexSize() // virtual class messageInfo getFolderIndexInfo(size_t)=0; // // Return the mail::messageInfo structure for an indicated message. // virtual void saveFolderIndexInfo(size_t messageNum, const messageInfo &msgInfo, callback &callback)=0; // // Reflect updated message flags. // // messageNum - update flags of this message // msgInfo - new message flags. virtual void updateFolderIndexFlags(const std::vector &messages, bool doFlip, bool enableDisable, const messageInfo &flags, callback &callback)=0; // // Update flags of multiple messages. // // messages - list of messages whose flags are to be updated. // // doFlip - flip the state of the indicated flags // // enableDisable - whether the indicated flags should be set, or // cleared (ignored if doFlip is set) // // flags - which flags should be changed. The flags structure is // NOT saved for each indicated message, instead the action specified // by doFlip/enableDisable is applied to each flag set in the flags // object. virtual void updateFolderIndexInfo(callback &)=0; // // Remove deleted messages. virtual void removeMessages(const std::vector &messages, callback &cb)=0; // Remove specified messages // Update keywords virtual void updateKeywords(const std::vector &messages, const std::set &keywords, bool setOrChange, // false: set, true: see changeTo bool changeTo, callback &cb); // Variations of the above. Implemented in the base class. void updateKeywords(const std::vector &messages, const std::vector &keywords, bool setOrChange, // false: set, true: see changeTo bool changeTo, callback &cb); void updateKeywords(const std::vector &messages, const std::list &keywords, bool setOrChange, // false: set, true: see changeTo bool changeTo, callback &cb); virtual void getFolderKeywordInfo(size_t, std::set &); // // Application requests to be notified about folder changes // immediately, if possible (IMAP IDLE) // virtual void updateNotify(bool enableDisable, callback &callbackArg); // // Update the folder according to the flags on each message. // Generally, each message with the deleted flag is set gets removed // from the folder. Additionally, updateFolderIndexInfo() usually // results in the applicatio notified regarding any changes to the // folder's contents, via mail::folderCallback's methods. virtual void copyMessagesTo(const std::vector &messages, folder *copyTo, callback &callback)=0; // // Copy messages to another folder // // messages - which message to copy // copyTo - a folder from the same, or another mail account. virtual void moveMessagesTo(const std::vector &messages, mail::folder *copyTo, mail::callback &callback); // // Like copyMessagesTo(), except that the messages are moved, not // copied (invoking mail::folderCallback::messagesRemoved() // appropriate. // Subclasses may override. The generic implementation uses // copyMessagesTo(), followed by removeMessages virtual void searchMessages(const searchParams &searchInfo, searchCallback &callback)=0; // // Search messages in this folder. // // searchInfo - specified the search criteria // // callback - callback object that receives the list of messages // that fit the search criteria }; // gcc food inline account::MessageAttributes operator| (account::MessageAttributes a, account::MessageAttributes b) { return (account::MessageAttributes)((int)a | (int)b); } inline account::MessageAttributes operator& (account::MessageAttributes a, account::MessageAttributes b) { return (account::MessageAttributes)((int)a & (int)b); } inline account::MessageAttributes &operator&= (account::MessageAttributes &a, account::MessageAttributes b) { return (a=(account::MessageAttributes)((int)a & (int)b)); } inline account::MessageAttributes operator~ (account::MessageAttributes a) { return (account::MessageAttributes)~(int)a; } // // A folder object represents a folder in a mail account. Each mail::folder // object is linked to the mail::account object that created it. class folder : public obj { ptr myServer; protected: bool isDestroyed(callback &callback) const; bool isDestroyed() const; folder(const folder &); // UNDEFINED folder &operator=(const folder &o) { myServer=o.myServer; return *this; } public: // Applications should not use the constructor directly, but instead // should use other methods in the mail::account and mail::folder objects // to create instances of mail::folder. Applications can destroy // mail::folder objects at any time where the object is not an // argument to an uncompleted request. folder(mail::account *); virtual ~folder(); virtual void sameServerAsHelperFunc() const=0; // // For internal use. // virtual std::string getName() const=0; // // Return the name of the folder, in the application character set. virtual std::string getPath() const=0; // // Return the folder's path. Applications should consider paths to // be complete opaque strings, for libmail.a's internal use only. // The only officially blessed usage for paths is as arguments for // mail::account::findFolder, and mail::folder::isParentOf(). virtual bool hasMessages() const=0; // // Return an indication whether this folder can contain message. virtual bool hasSubFolders() const=0; // // Return an indication whether this folder can contain subfolders. virtual std::string isNewsgroup() const; // // Returns a non-empty string if this is a newsgroup, with the // string being the newsgroup name. virtual bool isParentOf(std::string path) const=0; // True if this folder would be considered a parent folder in the // folder hierarchy. // // path - the path of another folder. virtual void hasMessages(bool)=0; virtual void hasSubFolders(bool)=0; // // For internal use only virtual void readFolderInfo( callback::folderInfo &callback1, callback &callback2) const=0; // Return folder metadata, such as the size of this folder virtual void getParentFolder(callback::folderList &callback1, callback &callback2) const=0; // Return parent folder virtual void readSubFolders( callback::folderList &callback1, callback &callback2) const=0; // Enumerate any subfolders in this folder virtual mail::addMessage *addMessage(callback &callback) const=0; // // Add a new message to this folder. Returns a mail::addMessage // object. // // callback - the usual callback object. // // If addMessage() returns NULL, callback.fail() will be invoked to // indicate the reason why. Otherwise, the new message's metadata // should be saved in the mail::addMessage's fields. // The message's contents must be passed to saveMessageContents() // (multiple times, if necessary), followed by // saveMessageContents::go(). If it becomes necessary to abort // the process, saveMessageContents::fail() will hold the presses, // invoke callback.fail(), and destroy the mail::addMessage object. virtual void createSubFolder(std::string name, bool isDirectory, callback::folderList &callback1, callback &callback2) const=0; // Create a new subfolder. // // name - the name of the new subfolder. // isDirectory - if true, the subfolder is expected to contain // subfolders. To create a folder that should contain both subfolders // and messages do this twice, first with isDirectory set to false, // then with isDirectory set to true. Note that not every mail // account supports dual-purpose folders. // callback1 - if succesfully, callback1.success() gets invoked with // a folder list containing the new folder directory entry. virtual void create(bool isDirectory, callback &callback) const=0; // // An alternative path to create a new folder is to use // mail::account::folderFromString() to create a folder object for a // folder that doesn't really exist, then use this method to create // the new folder. virtual void destroy(callback &callback, bool destroyDir) const=0; // // The opposite of create() - deletes this folder. destroyDir should // be set to indicate if this folder contains subfolders or messages. // For dual-purpose folders, only the folder component represented // by destroyDir() gets removed. virtual void renameFolder(const folder *newParent, std::string newName, callback::folderList &callback1, callback &callback2) const=0; // Rename this folder. // // newParent - new parent folder, or NULL if folder should be renamed // to the top of the hierarcy tree // newName - new folder name, in application charset // virtual folder *clone() const=0; // // Create another mail::folder object that refers to the same // folder. virtual std::string toString() const=0; // // Convert this folder's identity to a single string. Applications // should consider the string to be a completely opaque string; with // its only documented purpose is that passing the string to // mail::account::folderFromString() will create a mail::folder object that // refers to the same folder that this object refers to. virtual void open(callback &openCallback, snapshot *restoreSnapshot, callback::folder &folderCallback) const=0; // // Open the messages in this folder. Any existing open folder is // automatically closed. If the open fails, whether an existing folder // remains open is undefined. // // openCallback - the standard callback method whose methods will be // invoked to indicate whether the operation succeeded or not. // // If not NULL, a pointer to a snapshot object that holds a previously // saved folder index snapshot (see callback::folder::saveSnapshot). // // // folderCallback - the object whose methods will be invoked to notify // of any changes to the folder's state while it is opened. This // object must not be destroyed, and must continue to exist until // either another folder's open request succeeds, or the mail account // is closed or disconnected. // --------- Access control list support ---------- // virtual void getMyRights(callback &getCallback, std::string &rights) const; virtual void getRights(callback &getCallback, std::list > &rights) const; virtual void setRights(callback &setCallback, std::string &errorIdentifier, std::vector &errorRights, std::string identifier, std::string rights) const; virtual void delRights(callback &setCallback, std::string &errorIdentifier, std::vector &errorRights, std::string identifier) const; // Helper function for sorting folders. class sort { bool foldersFirst; public: sort(bool foldersFirstArg); ~sort(); bool operator()(const folder *a, const folder *b); }; }; // // A mail::callback::disconnect() object is provided for each request to // open a mail account. // When the connection to the mail account's server terminates, the object's // disconnected() method is invoked. If the connection was abnormally // terminated, the errmsg string will be empty. // The servererror() method may be invoked at any time to report a critical // server error that was not severe enough to force the connection to be // terminated. class callback::disconnect { public: disconnect() {} virtual ~disconnect() {} virtual void disconnected(const char *errmsg)=0; virtual void servererror(const char *errmsg)=0; }; // // Callbacks for readMessageContent(): // class callback::message : public callback { public: message(); virtual ~message(); virtual void messageEnvelopeCallback(size_t messageNumber, const envelope &envelopeArg); virtual void messageReferencesCallback(size_t messageNumber, const std::vector &references); virtual void messageArrivalDateCallback(size_t messageNumber, time_t datetime); virtual void messageSizeCallback(size_t messageNumber, unsigned long size); virtual void messageStructureCallback(size_t messageNumber, const mimestruct &messageStructure); virtual void messageTextCallback(size_t n, std::string text); }; // // A callback for readTopLevelFolders/readSubFolders: // This callback object is also used for creating a new folder. A // mail::callback::folderList object is provided when creating a new folder. // The success() method is invoked with a vector containing exactly one // mail::folder object, representing the newly-created folder. // // NOTE: The mail::folder objects provided to the success() method are valid // only until the success method() terminates, and are IMMEDIATELY destroyed // afterwards. If the callback function needs to preserve a mail::folder // object (perhaps for the application's main code, later, after it checks // that this request completed succesfully and needs to do something else to // the folder) it should use mail::folder::clone() method to create its own // private copy of the mail::folder object. class callback::folderList { public: folderList(); virtual ~folderList(); virtual void success(const std::vector &folders)=0; }; ///////////////////////////////////////////////////////////////////// // // Information about a folder class callback::folderInfo { public: size_t messageCount; size_t unreadCount; bool fastInfo; // Initialize to TRUE to only do this if it can be done fast. folderInfo(); virtual ~folderInfo(); virtual void success(); }; ///////////////////////////////////////////////////////////////////// // // A reference to the following object is saved when a folder is opened // // The object should be subclassed, and virtual methods implemented. // // libmail.a uses the object to notify the application about any changes // to the contents of the folder. The application should expect any of // the following methods to be invoked at any time. However, the methods // are usually invoked by mail::account::saveFolderIndexInfo(), // mail::account::updateFolderIndexFlags(), mail::account::updateFolderIndexInfo(), // and mail::account::checkNewMail(). Additionally, if the 'peek' argument to // mail::account::readMessageContents(), and mail::account::readMessageContentsDecoded() is // false, mail::folderCallback::messageChanged() will be invoked to indicate // that the message's unread flag has been reset. // // However, the application must be prepared to deal with any method being // invoked at any time, in the event that the mail account allows the same // folder to be opened by multiple applications, and another applications // makes changes to the folder. class callback::folder { public: folder(); virtual ~folder(); virtual void newMessages()=0; // // New messages have been added to the folder. The application // should use mail::account::getFolderIndexSize() to obtain the current // folder size, and compare it with the previously known folder // size in order to determine newly-added messages. virtual void messagesRemoved(std::vector< std::pair > &)=0; // // Messages were removed from the folder. messagesRemoved() receives // a reference to an array of first-last pairs. Each first-last // pair specifies a range of messages removed from the folder index. // <3, 5> indicates that messages 3, 4, and 5 were removed, // <3, 3> indicates that message #3 was removed. // // The array is sorted in numerically increasing order. virtual void messageChanged(size_t n)=0; // // Message metadata has changed. Use mail::account::getFolderIndexInfo() // to obtain the updated set of message flags. virtual void saveSnapshot(std::string snapshotId); // Optionally cache the current folder index (getFolderIndexInfo()), // as snapshot "snapshotId" }; // // libmail.a collects the following metadata about each message, when // a folder is opened. // The application is notified via mail::folderCallback::messageChanged() // about any changes to an existing message's metadata. // NOTE: this includes changes initiated by the application itself. // For example, mail::folderCallback::messageChanged() will usually be // invoked before the mail::account::saveFolderIndexInfo() request completes // Any changes to the following metadata are // The folder index. class messageInfo { public: std::string uid; // // A unique ID is assigned to each message in a folder. Applications // must consider the uid value to be a completely opaque string. // The only assumption that applications may make is that no two // messages will ever have the same uid in the same folder. // Not all mail accounts support the following flags. Where not, // libmail.a will simulate the semantics of the flag while the // mail account is opened. bool draft, // This is a draft message replied, // This message has been replied to marked, // This message is marked for further processing deleted, // Marked for deletion (updateFolderIndexInfo() // should end up removing this message unread, // The contents of this message have not been read. recent; // This is the first time the folder has been opened // with this message in the folder. #define LIBMAIL_MSGFLAGS \ do { \ DOFLAG( FLAG, draft, "\\DRAFT"); \ DOFLAG( FLAG, replied, "\\ANSWERED"); \ DOFLAG( FLAG, marked, "\\FLAGGED"); \ DOFLAG( FLAG, deleted, "\\DELETED"); \ DOFLAG(NOTFLAG, unread, "\\SEEN"); \ } while (0) #define LIBMAIL_SMAPFLAGS \ do {\ DOFLAG( FLAG, draft, "DRAFT");\ DOFLAG( FLAG, replied, "REPLIED");\ DOFLAG( FLAG, deleted, "DELETED");\ DOFLAG( FLAG, marked, "MARKED");\ DOFLAG(NOTFLAG, unread, "SEEN");\ } while (0) messageInfo(); ~messageInfo(); operator std::string() const; messageInfo(std::string); }; LIBMAIL_END #endif