diff options
Diffstat (limited to 'src/maildir-updateflags.cc')
-rw-r--r-- | src/maildir-updateflags.cc | 115 |
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(); + } +} |