aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/messaging/maildirFolder.cpp288
-rw-r--r--src/messaging/maildirFolder.hpp19
-rw-r--r--src/messaging/maildirMessage.hpp2
-rw-r--r--src/messaging/maildirUtils.cpp38
-rw-r--r--src/messaging/maildirUtils.hpp53
5 files changed, 357 insertions, 43 deletions
diff --git a/src/messaging/maildirFolder.cpp b/src/messaging/maildirFolder.cpp
index 155b48fc..8ae6b72c 100644
--- a/src/messaging/maildirFolder.cpp
+++ b/src/messaging/maildirFolder.cpp
@@ -261,59 +261,113 @@ void maildirFolder::scanFolder()
{
utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
- utility::auto_ptr <utility::file> newDir = fsf->create
- (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_NEW));
- utility::auto_ptr <utility::file> curDir = fsf->create
- (maildirUtils::getFolderFSPath(m_store, m_path, maildirUtils::FOLDER_PATH_CUR));
+ utility::file::path newDirPath = maildirUtils::getFolderFSPath
+ (m_store, m_path, maildirUtils::FOLDER_PATH_NEW);
+ utility::auto_ptr <utility::file> newDir = fsf->create(newDirPath);
- // Unread messages (new/)
+ utility::file::path curDirPath = maildirUtils::getFolderFSPath
+ (m_store, m_path, maildirUtils::FOLDER_PATH_CUR);
+ utility::auto_ptr <utility::file> curDir = fsf->create(curDirPath);
+
+ // New received messages (new/)
utility::auto_ptr <utility::fileIterator> nit = newDir->getFiles();
- std::vector <utility::path::component> unreadMessageFilenames;
+ std::vector <utility::file::path::component> newMessageFilenames;
while (nit->hasMoreElements())
{
utility::auto_ptr <utility::file> file = nit->nextElement();
- unreadMessageFilenames.push_back(file->fullPath().getLastComponent());
+ newMessageFilenames.push_back(file->fullPath().getLastComponent());
}
- // Seen messages (cur/)
+ // Current messages (cur/)
utility::auto_ptr <utility::fileIterator> cit = curDir->getFiles();
- std::vector <utility::path::component> messageFilenames;
+ std::vector <utility::file::path::component> curMessageFilenames;
while (cit->hasMoreElements())
{
utility::auto_ptr <utility::file> file = cit->nextElement();
- messageFilenames.push_back(file->fullPath().getLastComponent());
+ curMessageFilenames.push_back(file->fullPath().getLastComponent());
}
- // TODO: update m_messageFilenames
- // TODO: what to do with files which name has changed? (flag change, message deletion...)
+ // Update/delete existing messages (found in previous scan)
+ for (unsigned int i = 0 ; i < m_messageInfos.size() ; ++i)
+ {
+ messageInfos& msgInfos = m_messageInfos[i];
- m_unreadMessageCount = unreadMessageFilenames.size();
- m_messageCount = messageFilenames.size();
- }
- catch (exceptions::filesystem_exception&)
- {
- // Should not happen...
- }
+ // NOTE: the flags may have changed (eg. moving from 'new' to 'cur'
+ // may imply the 'S' flag) and so the filename. That's why we use
+ // "maildirUtils::messageIdComparator" to compare only the 'unique'
+ // portion of the filename...
- /*
- int m_unreadMessageCount;
- int m_messageCount;
+ if (msgInfos.type == messageInfos::TYPE_CUR)
+ {
+ const std::vector <utility::file::path::component>::iterator pos =
+ std::find_if(curMessageFilenames.begin(), curMessageFilenames.end(),
+ maildirUtils::messageIdComparator(msgInfos.path));
+
+ // If we cannot find this message in the 'cur' directory,
+ // it means it has been deleted (and expunged).
+ if (pos == curMessageFilenames.end())
+ {
+ msgInfos.type = messageInfos::TYPE_DELETED;
+ }
+ // Otherwise, update its information.
+ else
+ {
+ msgInfos.path = *pos;
+ curMessageFilenames.erase(pos);
+ }
+ }
+ }
- std::vector <folder::path::component> m_unreadMessageFilenames;
- std::vector <folder::path::component> m_messageFilenames;
+ // Add new messages from 'new': we are responsible to move the files
+ // from the 'new' directory to the 'cur' directory, and append them
+ // to our message list.
+ for (std::vector <utility::file::path::component>::const_iterator
+ it = newMessageFilenames.begin() ; it != newMessageFilenames.end() ; ++it)
+ {
+ // Move messages from 'new' to 'cur'
+ utility::auto_ptr <utility::file> file = fsf->create(newDirPath / *it);
+ file->rename(curDirPath / *it);
- if (0)
- {
- m_messageFilenames.clear();
+ // Append to message list
+ messageInfos msgInfos;
+ msgInfos.path = *it;
+ msgInfos.type = messageInfos::TYPE_CUR;
+
+ m_messageInfos.push_back(msgInfos);
+ }
+
+ // Add new messages from 'cur': the files have already been moved
+ // from 'new' to 'cur'. Just append them to our message list.
+ for (std::vector <utility::file::path::component>::const_iterator
+ it = curMessageFilenames.begin() ; it != curMessageFilenames.end() ; ++it)
+ {
+ // Append to message list
+ messageInfos msgInfos;
+ msgInfos.path = *it;
+ msgInfos.type = messageInfos::TYPE_CUR;
+
+ m_messageInfos.push_back(msgInfos);
+ }
- for (...)
+ // Update message count
+ int unreadMessageCount = 0;
+
+ for (std::vector <messageInfos>::const_iterator
+ it = m_messageInfos.begin() ; it != m_messageInfos.end() ; ++it)
{
- m_messageFilenames.push_back(...);
+ if ((maildirUtils::extractFlags((*it).path) & message::FLAG_SEEN) == 0)
+ ++unreadMessageCount;
}
+
+ m_unreadMessageCount = unreadMessageCount;
+ m_messageCount = m_messageInfos.size();
+ }
+ catch (exceptions::filesystem_exception&)
+ {
+ // Should not happen...
}
- */
}
@@ -436,19 +490,187 @@ void maildirFolder::rename(const folder::path& newPath)
void maildirFolder::deleteMessage(const int num)
{
- // TODO
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ if (m_messageInfos[num].type == messageInfos::TYPE_DELETED)
+ return;
+
+ m_messageInfos[num].type = messageInfos::TYPE_DELETED;
+
+ // Delete file from file system
+ try
+ {
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath = maildirUtils::getFolderFSPath
+ (m_store, m_path, maildirUtils::FOLDER_PATH_CUR);
+
+ utility::auto_ptr <utility::file> file = fsf->create
+ (curDirPath / m_messageInfos[num].path);
+
+ file->remove();
+ }
+ catch (exceptions::filesystem_exception& e)
+ {
+ // Ignore (not important)
+ }
+
+ // Update local flags
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if ((*it)->getNumber() == num &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags |= message::FLAG_DELETED;
+ }
+ }
+
+ // Notify message flags changed
+ std::vector <int> nums;
+ nums.push_back(num);
+
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, nums);
+
+ notifyMessageChanged(event);
}
void maildirFolder::deleteMessages(const int from, const int to)
{
- // TODO
+ if (from < 1 || (to < from && to != -1))
+ throw exceptions::invalid_argument();
+
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ const int to2 = (to == -1) ? m_messageCount : to;
+ const int count = to - from + 1;
+
+ // Delete files from file system
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath = maildirUtils::getFolderFSPath
+ (m_store, m_path, maildirUtils::FOLDER_PATH_CUR);
+
+ for (int i = from ; i <= to2 ; ++i)
+ {
+ if (m_messageInfos[i].type != messageInfos::TYPE_DELETED)
+ {
+ m_messageInfos[i].type = messageInfos::TYPE_DELETED;
+
+ try
+ {
+ utility::auto_ptr <utility::file> file = fsf->create
+ (curDirPath / m_messageInfos[i].path);
+
+ file->remove();
+ }
+ catch (exceptions::filesystem_exception& e)
+ {
+ // Ignore (not important)
+ }
+ }
+ }
+
+ // Update local flags
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if ((*it)->getNumber() >= from && (*it)->getNumber() <= to2 &&
+ (*it)->m_flags != message::FLAG_UNDEFINED)
+ {
+ (*it)->m_flags |= message::FLAG_DELETED;
+ }
+ }
+
+ // Notify message flags changed
+ std::vector <int> nums;
+ nums.resize(count);
+
+ for (int i = from, j = 0 ; i <= to2 ; ++i, ++j)
+ nums[j] = i;
+
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, nums);
+
+ notifyMessageChanged(event);
}
void maildirFolder::deleteMessages(const std::vector <int>& nums)
{
- // TODO
+ if (nums.empty())
+ throw exceptions::invalid_argument();
+
+ if (!m_store)
+ throw exceptions::illegal_state("Store disconnected");
+ else if (!isOpen())
+ throw exceptions::illegal_state("Folder not open");
+ else if (m_mode == MODE_READ_ONLY)
+ throw exceptions::illegal_state("Folder is read-only");
+
+ // Sort the list of message numbers
+ std::vector <int> list;
+
+ list.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), list.begin());
+
+ std::sort(list.begin(), list.end());
+
+ // Delete files from file system
+ utility::fileSystemFactory* fsf = platformDependant::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath = maildirUtils::getFolderFSPath
+ (m_store, m_path, maildirUtils::FOLDER_PATH_CUR);
+
+ for (std::vector <int>::const_iterator it =
+ list.begin() ; it != list.end() ; ++it)
+ {
+ const int num = *it;
+
+ if (m_messageInfos[num].type != messageInfos::TYPE_DELETED)
+ {
+ m_messageInfos[num].type = messageInfos::TYPE_DELETED;
+
+ try
+ {
+ utility::auto_ptr <utility::file> file = fsf->create
+ (curDirPath / m_messageInfos[num].path);
+
+ file->remove();
+ }
+ catch (exceptions::filesystem_exception& e)
+ {
+ // Ignore (not important)
+ }
+ }
+ }
+
+
+ // Update local flags
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it)
+ {
+ if (std::binary_search(list.begin(), list.end(), (*it)->getNumber()))
+ {
+ if ((*it)->m_flags != message::FLAG_UNDEFINED)
+ (*it)->m_flags |= message::FLAG_DELETED;
+ }
+ }
+
+ // Notify message flags changed
+ events::messageChangedEvent event(this, events::messageChangedEvent::TYPE_FLAGS, list);
+
+ notifyMessageChanged(event);
}
diff --git a/src/messaging/maildirFolder.hpp b/src/messaging/maildirFolder.hpp
index 65835219..96883736 100644
--- a/src/messaging/maildirFolder.hpp
+++ b/src/messaging/maildirFolder.hpp
@@ -27,6 +27,8 @@
#include "../types.hpp"
#include "folder.hpp"
+#include "../utility/file.hpp"
+
namespace vmime {
namespace messaging {
@@ -134,9 +136,22 @@ private:
int m_unreadMessageCount;
int m_messageCount;
- std::vector <folder::path::component> m_unreadMessageFilenames;
- std::vector <folder::path::component> m_messageFilenames;
+ // Store information about scanned messages
+ struct messageInfos
+ {
+ enum Type
+ {
+ TYPE_CUR,
+ TYPE_DELETED
+ };
+
+ utility::file::path::component path; // filename
+ Type type; // current location
+ };
+
+ std::vector <messageInfos> m_messageInfos;
+ // Instanciated message objects
std::vector <maildirMessage*> m_messages;
};
diff --git a/src/messaging/maildirMessage.hpp b/src/messaging/maildirMessage.hpp
index 83e7758f..7d2cd0d6 100644
--- a/src/messaging/maildirMessage.hpp
+++ b/src/messaging/maildirMessage.hpp
@@ -77,6 +77,8 @@ protected:
maildirFolder* m_folder;
int m_num;
+ int m_size;
+ int m_flags;
};
diff --git a/src/messaging/maildirUtils.cpp b/src/messaging/maildirUtils.cpp
index 2d294c0f..f6e16d8a 100644
--- a/src/messaging/maildirUtils.cpp
+++ b/src/messaging/maildirUtils.cpp
@@ -85,13 +85,23 @@ const bool maildirUtils::isSubfolderDirectory(const utility::file& file)
}
-/*
+const utility::file::path::component maildirUtils::extractId
+ (const utility::file::path::component& filename)
+{
+ string::size_type sep = filename.getBuffer().rfind(':');
+ if (sep == string::npos) return (filename);
+
+ return (utility::path::component
+ (string(filename.getBuffer().begin(), filename.getBuffer().begin() + sep)));
+}
+
+
const int maildirUtils::extractFlags(const utility::file::path::component& comp)
{
- string::size_type sep = comp.buffer().rfind(':');
+ string::size_type sep = comp.getBuffer().rfind(':');
if (sep == string::npos) return (0);
- const string flagsString(comp.buffer().begin() + sep + 1, comp.buffer().end());
+ const string flagsString(comp.getBuffer().begin() + sep + 1, comp.getBuffer().end());
const string::size_type count = flagsString.length();
int flags = 0;
@@ -102,6 +112,8 @@ const int maildirUtils::extractFlags(const utility::file::path::component& comp)
{
case 'S': case 's': flags |= message::FLAG_SEEN; break;
case 'R': case 'r': flags |= message::FLAG_REPLIED; break;
+
+ // TODO: more flags
}
}
@@ -109,6 +121,7 @@ const int maildirUtils::extractFlags(const utility::file::path::component& comp)
}
+/*
const utility::file::component maildirUtils::changeFlags
(const utility::file::component& comp, const int flags)
{
@@ -116,5 +129,24 @@ const utility::file::component maildirUtils::changeFlags
*/
+
+//
+// messageIdComparator
+//
+
+maildirUtils::messageIdComparator::messageIdComparator
+ (const utility::file::path::component& comp)
+ : m_comp(maildirUtils::extractId(comp))
+{
+}
+
+
+const bool maildirUtils::messageIdComparator::operator()
+ (const utility::file::path::component& other) const
+{
+ return (m_comp == maildirUtils::extractId(other));
+}
+
+
} // messaging
} // vmime
diff --git a/src/messaging/maildirUtils.hpp b/src/messaging/maildirUtils.hpp
index 44d36ad3..dddc735d 100644
--- a/src/messaging/maildirUtils.hpp
+++ b/src/messaging/maildirUtils.hpp
@@ -32,18 +32,37 @@ namespace messaging {
class maildirStore;
+/** Miscellaneous helpers functions for maildir messaging system.
+ */
+
class maildirUtils
{
public:
+ /** Comparator for message filenames, based only on the
+ * unique identifier part of the filename.
+ */
+ class messageIdComparator
+ {
+ public:
+
+ messageIdComparator(const utility::file::path::component& comp);
+
+ const bool operator()(const utility::file::path::component& other) const;
+
+ private:
+
+ const utility::file::path::component m_comp;
+ };
+
/** Mode for return value of getFolderFSPath(). */
enum FolderFSPathMode
{
- FOLDER_PATH_ROOT, /**< Root folder (eg. ~/Mail/MyFolder) */
- FOLDER_PATH_NEW, /**< Folder containing unread messages (eg. ~/Mail/MyFolder/new) */
- FOLDER_PATH_CUR, /**< Folder containing messages that have been seen (eg. ~/Mail/MyFolder/cur) */
- FOLDER_PATH_TMP, /**< Temporary folder used for reliable delivery (eg. ~/Mail/MyFolder/tmp) */
- FOLDER_PATH_CONTAINER /**< Container for sub-folders (eg. ~/Mail/.MyFolder.directory) */
+ FOLDER_PATH_ROOT, /**< Root folder. Eg: ~/Mail/MyFolder */
+ FOLDER_PATH_NEW, /**< Folder containing unread messages. Eg: ~/Mail/MyFolder/new */
+ FOLDER_PATH_CUR, /**< Folder containing messages that have been seen. Eg: ~/Mail/MyFolder/cur */
+ FOLDER_PATH_TMP, /**< Temporary folder used for reliable delivery. Eg: ~/Mail/MyFolder/tmp */
+ FOLDER_PATH_CONTAINER /**< Container for sub-folders. Eg: ~/Mail/.MyFolder.directory */
};
/** Return the path on the filesystem for the folder in specified store.
@@ -55,8 +74,32 @@ public:
*/
static const utility::file::path getFolderFSPath(maildirStore* store, const utility::path& folderPath, const FolderFSPathMode mode);
+ /** Test whether the specified file-system directory corresponds to
+ * a maildir sub-folder. The name of the directory should not start
+ * with '.' to be listed as a sub-folder.
+ *
+ * @return true if the specified directory is a maildir sub-folder,
+ * false otherwise
+ */
static const bool isSubfolderDirectory(const utility::file& file);
+ /** Extract the unique identifier part of the message filename.
+ * Eg: for the filename "1071577232.28549.m03s:2,RS", it will
+ * return "1071577232.28549.m03s".
+ *
+ * @return part of the filename that corresponds to the unique
+ * identifier of the message
+ */
+ static const utility::file::path::component extractId(const utility::file::path::component& filename);
+
+ /** Extract message flags from the specified message filename.
+ * Eg: for the filename "1071577232.28549.m03s:2,RS", it will
+ * return (message::FLAG_SEEN | message::FLAG_REPLIED).
+ *
+ * @return message flags extracted from the specified filename
+ */
+ static const int extractFlags(const utility::file::path::component& comp);
+
private:
static const vmime::word TMP_DIR;