summaryrefslogtreecommitdiff
path: root/src/maildir-updateflags.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/maildir-updateflags.cc')
-rw-r--r--src/maildir-updateflags.cc115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/maildir-updateflags.cc b/src/maildir-updateflags.cc
new file mode 100644
index 0000000..be37234
--- /dev/null
+++ b/src/maildir-updateflags.cc
@@ -0,0 +1,115 @@
+/** --------------------------------------------------------------------
+ * @file maildir-updateflags.cc
+ * @brief Implementation of the Maildir class.
+ * @author Andreas Aardal Hanssen
+ * @date 2002-2005
+ * ----------------------------------------------------------------- **/
+#include "maildir.h"
+
+#include <dirent.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "iodevice.h"
+#include "iofactory.h"
+
+using namespace ::std;
+
+//------------------------------------------------------------------------
+void Binc::Maildir::updateFlags(void)
+{
+ // don't update a read-only mailbox.
+ if (readOnly) return;
+
+ // open the cur/ directory
+ string curpath = path + "/cur/";
+ DIR *pdir = opendir(curpath.c_str());
+ if (pdir == 0) {
+ bincError << "failed to open " << curpath << ": "
+ << strerror(errno) << endl;
+ return;
+ }
+
+ // read all entries in the directory
+ vector<string> entries;
+ struct dirent *pdirent;
+ while ((pdirent = readdir(pdir)) != 0) {
+ string filename = pdirent->d_name;
+ if (filename[0] == '.')
+ continue;
+ entries.push_back(filename);
+ }
+ closedir(pdir);
+
+ bool customFlagsChanged = false;
+
+ // loop through all messages in cur/, and update the flags that have
+ // changed.
+ for (vector<string>::const_iterator it = entries.begin(); it != entries.end(); ++it) {
+ string filename = *it;
+
+ // separate the unique name from the flags. accept messages that do not
+ // contain the flags section.
+ string uniquename;
+ string::size_type pos;
+ if ((pos = filename.find(":2,")) != string::npos)
+ uniquename = filename.substr(0, pos);
+ else
+ uniquename = filename;
+
+ // only update flags for messages that are known.
+ MaildirMessage *message = get(uniquename);
+ if (!message)
+ continue;
+
+ // check if custom flags have changed; if so, we need to regenerate the
+ // cache file.
+ if (message->internalFlags & MaildirMessage::CustomFlagsChanged)
+ customFlagsChanged = true;
+
+ // generate the flag string.
+ string flags;
+ int mflags = message->getStdFlags();
+ if (mflags & Message::F_DRAFT) flags += "D";
+ if (mflags & Message::F_FLAGGED) flags += "F";
+ if (mflags & Message::F_PASSED) flags += "P";
+ if (mflags & Message::F_ANSWERED) flags += "R";
+ if (mflags & Message::F_SEEN) flags += "S";
+ if (mflags & Message::F_DELETED) flags += "T";
+
+ // prepare the old and new message name. if equal, skip to the next
+ // message.
+ string srcname = curpath + filename;
+ string destname = curpath + uniquename + ":2," + flags;
+ if (srcname == destname)
+ continue;
+
+ // rename the file
+ if (rename(srcname.c_str(), destname.c_str()) != 0) {
+ if (errno == ENOENT) {
+ closedir(pdir);
+ if ((pdir = opendir(curpath.c_str())) == 0) {
+ bincError << "failed to open " << curpath << ": "
+ << strerror(errno) << endl;
+ return;
+ }
+
+ // restart scan. this catches the race condition where concurrent
+ // clients may have set a flag or removed the message.
+ continue;
+ }
+
+ bincError << "failed to rename " << srcname
+ << " to " << destname << ": "
+ << strerror(errno) << endl;
+ } else {
+ index.insert(uniquename, 0, uniquename + ":2," + flags);
+ }
+ }
+
+ // finally, regenerate the cache file if the custom flags have changed.
+ if (customFlagsChanged) {
+ Lock lock(path);
+ writeCache();
+ }
+}