Code Search for Developers
 
 
  

IMAPFolder.h from AlphaMail at Krugle


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

AlphaMail

AlphaMail is an accelerated web mail interface with a C++ middleware layer that is more effective than an IMAP proxy which is a highly scalable (10k+ users). The interface includes modern features, Section 508 compliance, and universal browser support.

Project homepage: http://sourceforge.net/projects/alphamail
Programming language(s): C++,Java,JavaScript,Perl
License: other

  CacheManager.h
  IMAPFolder.h
  IMAPParser.h
  IMAPRegexParser.h
  IMAPTypes.h
  MessageAttributes.h
  RequestProcessor.h
  Runnable.h
  imap_debug.h
  middleware.h