Show IMAPFolder.h syntax highlighted
#ifndef IMAP_IMAPFOLDER_H
#define IMAP_IMAPFOLDER_H 1
#ifdef CWDEBUG
#include "sys.h"
#include "debug.h"
#endif
#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <IMAPTypes.h>
#include <IMAPParser.h>
#include <RequestProcessor.h>
#include <netxx/netxx.h>
#include <netxx/tls/netxx.h>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <IMAPTypes.h>
#include <time.h>
namespace IMAP
{
/**
* <P>This class is intended to manage the cached data for a specific folder
* for a user's mail account. It takes into consideration that a user might
* have thousands of messages, and a very large quota. As a result, it tries
* to minimize memory usage.
*
* <P>Since this class is meant to serve as part of a caching system for
* thousands of users on a webmail system, there are several configurable
* caching parameters that make sense given the nature of web access. These
* are configured via the CacheManager (@see
* Middleware::CacheManager::theCacheManager)
*
* <P>The primary considerations are:
*
* <ol>
* <li> The web application will only display a limited number of message
* headers at once (maybe 10-50 at a time).
* <li> The caching system should be able to query the memory usage of a
* folder cache to get an idea of how much memory is in use.
* <li> The caching system should be able to ask a folder cache to free
* up what it can on-demand. The folder cache will try to keep at least
* the most recently viewed page of message headers.
* </ol>
*
* The IMAPFolder will maintain the connection to the IMAP server. This
* allows the web application to behave just like a regular IMAP client, and
* minimizes the impact of use, since commands like NOOP will be able to
* keep track of folder changes. Thus, things like checking for new mail
* becomes a very cheap operation.
*/
class IMAPFolder : private boost::noncopyable
{
public:
/**
* Create an IMAPFolder, log into the server, and select the given
* folder.
*
* @throws BadFolder if the select fails.
* @throws IMAPError if there is some other imap error
*/
IMAPFolder(std::string folder_name, const std::string &host,
const std::string &user, const std::string &password,
bool create = false);
/**
* Log out of the imap server, and clear all cached data for the folder.
*/
virtual ~IMAPFolder() {}
/**
* Get the number of messages in the folder.
*
* @returns The number of messages in the folder.
*/
int getMessageCount() {
boost::recursive_try_mutex::scoped_lock lk(object_mutex, true);
return exists;
}
/**
* Get the number of unread messages.
*/
int getUnseenMessageCount() {
boost::recursive_try_mutex::scoped_lock lk(object_mutex, true);
return unseen;
}
/**
* Get the time of the last change to the folder (i.e. the last time the
* message count changed.
*/
time_t getLastChangeTime() {
boost::recursive_try_mutex::scoped_lock lk(object_mutex, true);
return last_change_time;
}
/**
* Get the current value of the UID validity. If the imap folder has to
* reconnect (due to a dropped connection, or simultaneous access from
* another imap client), it is possible for the uid validity to change.
* If the uid validity changes, then all cached data must be cleared
* since it is keyed by uid.
*/
IMAPUID getUIDValidity() {
boost::recursive_try_mutex::scoped_lock lk(object_mutex, true);
return uidvalidity;
}
/**
* Verify that the given password matches the original connection
* password. This is required since the connections are cached. The user
* might log out of the web app, and normally we rely on the constructor
* to give auth errors. In the cached case, this method is used to verify
* identity.
*/
bool checkPassword(const std::string &pw) {
boost::recursive_try_mutex::scoped_lock lk(object_mutex, true);
return (pw == password);
}
enum SortOrder {
ByDate,
ByFrom,
ByThread,
ByTo,
};
/**
* Get a list of message attributes, and store them in the provided
* MessageList object. The sort order is implemented by sorting the
* message list itself. For threaded messages, a special attribute
* (threadlevel) is added to each message to assist the client in
* displaying the resulting list.
*
* Note that the MessageList is a list of CacheEntry objects, and the
* IMAPFolder will cache those same items in local CacheEntry objects. If
* a cleanup loop happens, it is possible that the folder will delete the
* cache entries; however, the actual attributes will continue to exist
* until the cache entries of the returned message list are also
* destroyed.
*
* @param list A place to store the results.
* @param start The starting message offset into the folder.
* @param n The number of messages to pull.
* @param order The sort order of the list.
*/
void getMessageList(MessageList *list, int start, int n, SortOrder sort = ByDate);
/**
* Add thread levels for the specified messages as attributes. A
* thread_level MessageAttribute is added to each message.
*
* @param list A reference to the message list the contains the messages
* to be marked up.
*/
void markThreadLevels(MessageList &list);
/**
* Clean up any unnecessary cached data. This drops everything in the
* message map that is older than CacheManager.getMinimumCacheTime()
* seconds.
*/
void cleanup();
/**
* Approximate current size of cached data in bytes. Note that it is
* impossible to account for some of the overhead, so this number is
* approximate.
*/
u_int32_t getCachedSize();
/**
* Get the complete RFC822 MIME message, and stream it over the supplied
* ostream object.
*
* A call to this method causes the message to be marked as read.
*
* @param uidv The UID validity of the folder, as obtained from a message
* list.
* @param uid The UID of the message desired.
* @param stream An ostream onto which the message should be streamed
* @returns True if the message was transferred, false otherwise. False
* indicates an invalid request, and usually means that your uid validity
* is out of sync with the underlying folder connection.
*/
bool streamMIMEMessage(const IMAPUID &uidv, const IMAPUID &uid, std::ostream &stream);
/**
* Append a message to the folder.
*
* @param size the incoming size of the message.
* @param source An input stream from which the message (in RFC822
* format) should be read.
*/
bool appendMIMEMessage(int size, std::istream &source);
/**
* Move a message from this folder to a different folder.
*
* @param uidvalidity The uidvalidity of this folder
* @param uid The uid of the message you want to transfer
* @param dest_name The name of the destination folder.
*
* @returns True if the message was moved, false otherwise.
*/
bool moveMessage(const IMAPUID &uidvalidity, const IMAPUID &uid,
const std::string &dest_name);
/**
* Mark/unmark the message as deleted. It will be removed from the folder
* when this folder is expunged if it is marked as deleted.
*
* @param uidvalidity The uidvalidity that the UID goes with
* @param uid The UID of the message to mark
* @param value Set it or unset it?
*
* @return True on success, false otherwise
*/
bool setDeleted(const IMAPUID &uidvalidity, const IMAPUID &uid,
bool value);
/**
* Mark/unmark a flag on the message.
*
* @param uidvalidity The uidvalidity that the UID goes with
* @param uid The UID of the message to mark
* @param flag The flag to affect.
* @param value Set it or unset it?
*
* @return True on success, false otherwise
*/
bool setFlag(const IMAPUID &uidvalidity, const IMAPUID &uid,
IMAPFlags flag, bool set);
/**
* Remove the messages that are marked for deletion.
*/
bool expunge();
/**
* Get a UID list of messages in sorted order. Never access the lists
* directly, because they can be cleared due to reconnect. This insures
* that the uid lists are properly retrieved, updated, and cached.
*
* @param order The sorting order you want.
*
* @returns a pointer to a UIDList. This pointer is always good, but
* should not be relied upon over reconnect() calls, since the underlying
* list might be cleared. Always call this function again if it is
* possible that a reconnect was necessary.
*/
const UIDList *getSortlist(IMAP::IMAPFolder::SortOrder order);
/**
* Get the actual iostream that is connected to the IMAP server. This is
* required for some commands that are unrelated to direct folder access
* (such as creating a folder).
*
* FIXME: Get rid of this! Plan:
*
* Commands that use this from RequestProcessor:
* do_list - Add a flag to IMAPFolder that indicates selectability, so
* that commands that do not make sense on a directory fail. Then
* RequestProcessor should just get an IMAPFolder for the base
* itself, and run list on it.
* set_subscribed_folders - Same as do_list
* create_folder - Add a flag to the constructor that indicates
* creation if not found
* delete_folder - Add a delete method. Once called, the IMAPFolder
* object itself becomes invalid to use.
*/
std::iostream &getIOStream();
/**
* Subscribe to a folder.
* @param folder the name of the folder to subscribe to. If not supplied,
* it assumes you want to subscribe to the folder that is represented by
* the invoking object.
*/
bool subscribe(const std::string &f = std::string(""));
bool getSubscribed(const std::string &base, FolderList *list);
bool unsubscribe(const std::string &f = std::string(""));
/**
* Cycle the actual IMAP connection, attempting to clear an early
* Goodbye. FIXME: Once getIOStream() is gone, make this private.
*/
void reconnect();
private:
/**
* Fill the sortlist given a sorting order.
*/
void fill_sortlist(IMAP::IMAPFolder::SortOrder order);
void fill_date_list();
void fill_thread_list();
void fill_from_list();
void fill_to_list();
void fill_sorted_list(UIDList *list, const char *key);
/**
* Check to see if mailbox has changed. This method should be run
* after any IMAP interaction through the parser to see if the counts
* or UIDV have changed. If so, it updates the internal counts, and
* updates the change time so that sort list will be updated.
*/
void check_for_updates(const boost::scoped_ptr<IMAP::IMAPParser> &parser,
IMAP::IMAPParser::ParsingState state);
bool check_uidvalidity(const boost::scoped_ptr<IMAP::IMAPParser> &parser);
/*
* These are the connection and parser variables
*/
boost::scoped_ptr<Netxx::TLS::Stream> connection;
boost::scoped_ptr<Netxx::Netbuf<1024> > streambuffer;
boost::scoped_ptr<std::iostream> server;
boost::scoped_ptr<IMAP::IMAPParser> parser;
/*
* Information about the folder
*/
std::string user, password, host, folder;
MessageMap messages; // Cached attributes
// Sorted UID lists
UIDList messages_by_date;
UIDList messages_by_thread;
UIDList messages_by_from;
UIDList messages_by_to;
// Indentation levels for threads
ThreadLevelMap thread_levels;
time_t mbd_filltime; // Last time the lists were populated
time_t mbt_filltime; // i.e. mbt = messages by thread
time_t mbf_filltime;
time_t mbto_filltime;
// Last time the list of messages in the folder changed on the imap
// server
time_t last_change_time;
int exists, recent, unseen;
IMAP::IMAPUID uidvalidity;
//static Netxx::TLS::Context *ssl_context;
// Mutlithread mutex for object-level protection
boost::recursive_try_mutex object_mutex;
// RequestProcessor needs to lock this object when using its parser
// and stream:
friend class Middleware::RequestProcessor;
// Last known size, in case the object is locked when cache manager
// needs to know.
u_int32_t last_known_size;
};
};
#endif
See more files for this project here