/** * @file maildir-updateflags.cc * @brief Implementation of the Maildir class. * @author Andreas Aardal Hanssen * @date 2002-2005 */ #include "iodevice.h" #include "iofactory.h" #include "maildir.h" #include #include #include using std::string; 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 == nullptr) { bincError << "failed to open " << curpath << ": " << strerror(errno) << std::endl; return; } // read all entries in the directory std::vector entries; struct dirent *pdirent; while ((pdirent = readdir(pdir)) != nullptr) { 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 (const auto &filename : entries) { // 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())) == nullptr) { bincError << "failed to open " << curpath << ": " << strerror(errno) << std::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) << std::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(); } }