diff options
Diffstat (limited to 'src/maildirmessage.cc')
-rw-r--r-- | src/maildirmessage.cc | 1153 |
1 files changed, 1153 insertions, 0 deletions
diff --git a/src/maildirmessage.cc b/src/maildirmessage.cc new file mode 100644 index 0000000..a78a5b9 --- /dev/null +++ b/src/maildirmessage.cc @@ -0,0 +1,1153 @@ +/** -------------------------------------------------------------------- + * @file maildirmessage.cc + * @brief Implementation of the MaildirMessage class. + * @author Andreas Aardal Hanssen + * @date Copyright 2002-2005 + * ----------------------------------------------------------------- **/ +#include <string> + +#include <stack> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> +#include <time.h> +#include <utime.h> + +#include "maildir.h" +#include "maildirmessage.h" +#include "convert.h" +#include "mime.h" +#include "iodevice.h" +#include "iofactory.h" +#include "mime-utils.h" +#include "mime-inputsource.h" + +using namespace ::std; +using namespace Binc; + +string Message::lastError; +string MaildirMessage::storage; + +namespace { + //---------------------------------------------------------------------- + void printOneHeader(IODevice &io, const MimePart *message, + const string &s_in, bool removecomments = true) + { + string tmp = ""; + HeaderItem hitem; + + if (message->h.getFirstHeader(s_in, hitem)) { + tmp = hitem.getValue(); + io << toImapString(unfold(tmp, removecomments)); + } else + io << "NIL"; + } + + //---------------------------------------------------------------------- + void printOneAddressList(IODevice &io, const MimePart *message, + const string &s_in, bool removecomments = true) + { + string tmp = ""; + HeaderItem hitem; + + if (message->h.getFirstHeader(s_in, hitem)) { + tmp = hitem.getValue(); + vector<string> addr; + splitAddr(unfold(tmp, removecomments), addr); + if (addr.size() != 0) { + io << "("; + for (vector<string>::const_iterator i = addr.begin(); + i != addr.end(); ++i) + + io << Address(*i).toParenList(); + io << ")"; + } else io << "NIL"; + } else + io << "NIL"; + } + + //---------------------------------------------------------------------- + void envelope(IODevice &io, const MimePart *message) + { + HeaderItem hitem; + io << "("; + printOneHeader(io, message, "date"); + io << " "; + printOneHeader(io, message, "subject", false); + io << " "; + printOneAddressList(io, message, "from", false); + io << " "; + printOneAddressList(io, message, + message->h.getFirstHeader("sender", hitem) + ? "sender" : "from", false); + io << " "; + printOneAddressList(io, message, + message->h.getFirstHeader("reply-to", hitem) + ? "reply-to" : "from", false); + io << " "; + printOneAddressList(io, message, "to", false); + io << " "; + printOneAddressList(io, message, "cc", false); + io << " "; + printOneAddressList(io, message, "bcc", false); + io << " "; + printOneHeader(io, message, "in-reply-to"); + io << " "; + printOneHeader(io, message, "message-id"); + io << ")"; + } + + //---------------------------------------------------------------------- + void bodyStructure(IODevice &io, const MimePart *message, bool extended) + { + HeaderItem hitem; + if (message->isMultipart() && message->members.size() > 0) { + io << "("; + + for (vector<MimePart>::const_iterator i = message->members.begin(); + i != message->members.end(); ++i) + bodyStructure(io, &(*i), extended); + + io << " "; + io << toImapString(message->getSubType()); + + if (extended) { + io << " "; + + vector<string> parameters; + vector<string> headers; + string tmp; + + string type, subtype; + + tmp = ""; + if (message->h.getFirstHeader("content-type", hitem)) { + tmp = unfold(hitem.getValue()); + trim(tmp); + + vector<string> v; + split(tmp, ";", v); + + for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i) { + string element = *i; + trim(element); + if (element.find('=') != string::npos) { + string::size_type pos = element.find('='); + string s = element.substr(0, pos); + string t = element.substr(pos + 1); + trim(s, " \""); + trim(t, " \""); + parameters.push_back(s); + parameters.push_back(t); + } + } + + if (parameters.size() != 0) { + io << "("; + for (vector<string>::const_iterator i = parameters.begin(); + i != parameters.end(); ++i) { + if (i != parameters.begin()) io << " "; + io << toImapString(*i); + } + io << ")"; + } else + io << "NIL"; + } else + io << "NIL"; + + // CONTENT-DISPOSITION + io << " "; + tmp = ""; + if (message->h.getFirstHeader("content-disposition", hitem)) { + tmp = hitem.getValue(); + trim(tmp); + + vector<string> v; + split(tmp, ";", v); + if (v.size() > 0) { + string disp = v[0]; + trim(disp); + io << "(" << toImapString(disp); + io << " "; + if (v.size() > 1) { + io << "("; + vector<string>::const_iterator i = v.begin(); + ++i; + bool wrote = false; + while (i != v.end()) { + string s = *i; + trim(s); + string::size_type pos = s.find('='); + string key = s.substr(0, pos); + string value = s.substr(pos + 1); + + trim(key); + trim(value); + + trim(key, " \""); + trim(value, " \""); + + if (!wrote) wrote = true; + else io << " "; + + io << toImapString(key); + io << " "; + io << toImapString(value); + + ++i; + } + io << ")"; + } else + io << "NIL"; + io << ")"; + } else + io << "NIL"; + } else + io << "NIL"; + + // CONTENT-LANGUAGE + io << " "; + printOneHeader(io, message, "content-language"); + } + io << ")"; + } else { + io << "("; + + vector<string> parameters; + vector<string> headers; + string tmp; + tmp = ""; + string type, subtype; + + tmp = ""; + if (message->h.getFirstHeader("content-type", hitem)) { + tmp = unfold(hitem.getValue()); + + vector<string> v; + split(tmp, ";", v); + + if (v.size() > 0) { + vector<string> b; + split(v[0], "/", b); + + if (b.size() > 0) + type = b[0]; + else + type = "text"; + + if (b.size() > 1) + subtype = b[1]; + else + subtype = "plain"; + } + + for (vector<string>::const_iterator i = v.begin(); i != v.end(); ++i) { + if (i == v.begin()) continue; + string element = *i; + trim(element); + if (element.find('=') != string::npos) { + string::size_type pos = element.find('='); + string s = element.substr(0, pos); + string t = element.substr(pos + 1); + trim(s, " \""); + trim(t, " \""); + parameters.push_back(s); + parameters.push_back(t); + } + } + + } else { + type = "text"; + subtype = "plain"; + } + + io << toImapString(type); + io << " "; + io << toImapString(subtype); + + io << " "; + if (parameters.size() != 0) { + io << "("; + for (vector<string>::const_iterator i = parameters.begin(); + i != parameters.end(); ++i) { + if (i != parameters.begin()) + io << " "; + io << toImapString(*i); + } + io << ")"; + } else + io << "NIL"; + + // CONTENT-ID + io << " "; + printOneHeader(io, message, "content-id"); + + // CONTENT-DESCRIPTION + io << " "; + printOneHeader(io, message, "content-description"); + + // CONTENT-TRANSFER-ENCODING + io << " "; + tmp = ""; + if (message->h.getFirstHeader("content-transfer-encoding", hitem)) { + tmp = hitem.getValue(); + trim(tmp); + io << toImapString(tmp); + } else + io << "\"7bit\""; + io << " "; + + // Size of body in octets + io << message->getBodyLength(); + + lowercase(type); + if (type == "text") { + io << " "; + io << message->getNofBodyLines(); + } else if (message->isMessageRFC822()) { + io << " "; + envelope(io, &message->members[0]); + io << " "; + bodyStructure(io, &message->members[0], extended); + io << " "; + io << message->getNofBodyLines(); + } + + // Extension data follows + + if (extended) { + // CONTENT-MD5 + io << " "; + printOneHeader(io, message, "content-md5"); + + // CONTENT-DISPOSITION + io << " "; + tmp = ""; + if (message->h.getFirstHeader("content-disposition", hitem)) { + tmp = hitem.getValue(); + trim(tmp); + vector<string> v; + split(tmp, ";", v); + if (v.size() > 0) { + string disp = v[0]; + trim(disp); + io << "(" << toImapString(disp); + io << " "; + if (v.size() > 1) { + io << "("; + vector<string>::const_iterator i = v.begin(); + ++i; + bool wrote = false; + while (i != v.end()) { + string s = *i; + trim(s); + string::size_type pos = s.find('='); + string key = s.substr(0, pos); + string value = s.substr(pos + 1); + trim(key); + trim(value); + trim(key, " \""); + trim(value, " \""); + if (!wrote) wrote = true; + else io << " "; + io << toImapString(key); + io << " "; + io << toImapString(value); + ++i; + } + io << ")"; + } else + io << "NIL"; + io << ")"; + } else + io << "NIL"; + } else + io << "NIL"; + + // CONTENT-LANGUAGE + io << " "; + printOneHeader(io, message, "content-language"); + + // CONTENT-LOCATION + io << " "; + printOneHeader(io, message, "content-location"); + } + + io << ")"; + } + } +} + +//------------------------------------------------------------------------ +MaildirMessage::MaildirMessage(Maildir &hom) + : fd(-1), doc(0), internalFlags(None), stdflags(F_NONE), + uid(0), size(0), unique(""), safeName(""), internaldate(0), + home(hom), customFlags(0) +{ +} + +//------------------------------------------------------------------------ +MaildirMessage::MaildirMessage(const MaildirMessage ©) + : fd(copy.fd), doc(copy.doc), internalFlags(copy.internalFlags), + stdflags(copy.stdflags), uid(copy.uid), size(copy.size), + unique(copy.unique), safeName(copy.safeName), + internaldate(copy.internaldate), home(copy.home) +{ + if (copy.customFlags) { + customFlags = new vector<string>; + *customFlags = *copy.customFlags; + } else { + customFlags = 0; + } +} + +//------------------------------------------------------------------------ +MaildirMessage::~MaildirMessage(void) +{ + delete customFlags; +} + +//------------------------------------------------------------------------ +MaildirMessage &MaildirMessage::operator =(const MaildirMessage ©) +{ + fd = copy.fd; + doc = copy.doc; + internalFlags = copy.internalFlags; + stdflags = copy.stdflags; + uid = copy.uid; + size = copy.size; + unique = copy.unique; + safeName = copy.safeName; + internaldate = copy.internaldate; + home = copy.home; + + if (copy.customFlags) { + customFlags = new vector<string>; + *customFlags = *copy.customFlags; + } else { + customFlags = 0; + } + + return *this; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::operator <(const MaildirMessage &a) const +{ + return uid < a.uid; +} +//------------------------------------------------------------------------ +void MaildirMessage::close(void) +{ + if (fd != -1) { + if ((internalFlags & WasWrittenTo) && fsync(fd) != 0 + && errno != EINVAL && errno != EROFS) { + // FIXME: report this error + } + + if (::close(fd) != 0) { + // FIXME: report this error + } + + fd = -1; + } + + // The file will not be moved from tmp/ before this function has + // finished. So it's safe to assume that safeName is still valid. + if (internalFlags & WasWrittenTo) { + if (internaldate != 0) { + struct utimbuf tim = {internaldate, internaldate}; + utime(safeName.c_str(), &tim); + } else { + time_t t = time(0); + struct utimbuf tim = {t, t}; + utime(safeName.c_str(), &tim); + } + + internalFlags &= ~WasWrittenTo; + } + + + if (doc) { + doc->clear(); + delete doc; + doc = 0; + } +} + +//------------------------------------------------------------------------ +void MaildirMessage::setExpunged(void) +{ + internalFlags |= Expunged; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setUnExpunged(void) +{ + internalFlags &= ~Expunged; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setFlagsUnchanged(void) +{ + internalFlags &= ~FlagsChanged; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::hasFlagsChanged(void) const +{ + return (internalFlags & FlagsChanged) != 0; +} + +//------------------------------------------------------------------------ +unsigned char MaildirMessage::getStdFlags(void) const +{ + return stdflags; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::isExpunged(void) const +{ + return (internalFlags & Expunged) != 0; +} + +//------------------------------------------------------------------------ +unsigned int MaildirMessage::getUID(void) const +{ + return uid; +} + +//------------------------------------------------------------------------ +unsigned int MaildirMessage::getSize(bool render) const +{ + if (size == 0 && render) { + size = getDocSize(); + home.mailboxchanged = true; + } + + return size; +} + +//------------------------------------------------------------------------ +const string &MaildirMessage::getUnique(void) const +{ + return unique; +} + +//------------------------------------------------------------------------ +time_t MaildirMessage::getInternalDate(void) const +{ + return internaldate; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setInternalDate(time_t t) +{ + internaldate = t; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setStdFlag(unsigned char f_in) +{ + internalFlags |= FlagsChanged; + stdflags |= f_in; +} + +//------------------------------------------------------------------------ +void MaildirMessage::resetStdFlags(void) +{ + internalFlags |= FlagsChanged; + stdflags = F_NONE; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setUID(unsigned int i_in) +{ + uid = i_in; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setSize(unsigned int i_in) +{ + size = i_in; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setUnique(const string &s_in) +{ + unique = s_in; +} + +//------------------------------------------------------------------------ +int MaildirMessage::getFile(void) const +{ + if (fd != -1) + return fd; + + const string &id = getUnique(); + MaildirIndexItem *item = home.index.find(id); + if (item) { + string fpath = home.path + "/cur/" + item->fileName; + + unsigned int oflags = O_RDONLY; +#ifdef HAVE_OLARGEFILE + oflags |= O_LARGEFILE; +#endif + while ((fd = open(fpath.c_str(), oflags)) == -1) { + if (errno == ENOENT) { + struct stat st; + if (lstat(fpath.c_str(), &st) != -1) { + bincWarning << "dangling symlink: " << fpath << endl; + return -1; + } + } else { + bincWarning << "unable to open " << fpath << ": " + << strerror(errno) << endl; + return -1; + } + + home.scanFileNames(); + if ((item = home.index.find(id)) == 0) + break; + else + fpath = home.path + "/cur/" + item->fileName; + } + + MaildirMessageCache &cache = MaildirMessageCache::getInstance(); + cache.addStatus(this, MaildirMessageCache::NotParsed); + + return fd; + } + + return -1; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setFile(int fd) +{ + this->fd = fd; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setSafeName(const string &name) +{ + safeName = name; +} + +//------------------------------------------------------------------------ +const string &MaildirMessage::getSafeName(void) const +{ + return safeName; +} + +//------------------------------------------------------------------------ +string MaildirMessage::getFileName(void) const +{ + MaildirIndexItem *item = home.index.find(getUnique()); + if (!item) { + home.scanFileNames(); + + if ((item = home.index.find(getUnique())) == 0) + return ""; + } + + return item->fileName; +} + +//------------------------------------------------------------------------ +int MaildirMessage::readChunk(string &chunk) +{ + if (fd == -1) { + if ((fd = getFile()) == -1) + return -1; + } + + char buffer[1024]; + ssize_t readBytes = read(fd, buffer, (size_t) sizeof(buffer)); + if (readBytes == -1) { + setLastError("Error reading from " + getFileName() + + ": " + string(strerror(errno))); + return -1; + } + + chunk = string(buffer, readBytes); + return readBytes; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::appendChunk(const string &chunk) +{ + if (fd == -1) { + setLastError("Error writing to " + getSafeName() + + ": File is not open"); + return false; + } + + internalFlags |= WasWrittenTo; + + string out; + for (string::const_iterator i = chunk.begin(); i != chunk.end(); ++i) { + const char c = *i; + if (c != '\r') + out += c; + } + + ssize_t wroteBytes = 0; + for (;;) { + wroteBytes = write(fd, out.c_str(), (size_t) out.length()); + if (wroteBytes == -1) { + if (errno == EINTR) + continue; + wroteBytes = 0; + } + + break; + } + + if (wroteBytes == (ssize_t) out.length()) + return true; + + setLastError("Error writing to " + getSafeName() + + ": " + string(strerror(errno))); + return false; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::parseFull(void) const +{ + MaildirMessageCache &cache = MaildirMessageCache::getInstance(); + MaildirMessageCache::ParseStatus ps = cache.getStatus(this); + if (ps == MaildirMessageCache::AllParsed && doc) + return true; + + int fd = getFile(); + if (fd == -1) + return false; + + // FIXME: parse errors + if (!doc) + doc = new MimeDocument; + doc->parseFull(fd); + + cache.addStatus(this, MaildirMessageCache::AllParsed); + + return true; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::parseHeaders(void) const +{ + MaildirMessageCache &cache = MaildirMessageCache::getInstance(); + MaildirMessageCache::ParseStatus ps = cache.getStatus(this); + if ((ps == MaildirMessageCache::AllParsed + || ps == MaildirMessageCache::HeaderParsed) && doc) + return true; + + int fd = getFile(); + if (fd == -1) + return false; + + // FIXME: parse errors + if (!doc) + doc = new MimeDocument; + doc->parseOnlyHeader(fd); + + cache.addStatus(this, MaildirMessageCache::HeaderParsed); + + return true; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::printBodyStructure(bool extended) const +{ + if (!parseFull()) + return false; + + bodyStructure(bincClient, doc, extended); + return true; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::printEnvelope(void) const +{ + if (!parseFull()) + return false; + + envelope(bincClient, doc); + return true; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::printHeader(const std::string §ion, + std::vector<std::string> headers, + bool includeHeaders, + unsigned int startOffset, + unsigned int length, + bool mime) const +{ + bincClient << storage; + storage = ""; + return true; +} + +//------------------------------------------------------------------------ +unsigned int MaildirMessage::getHeaderSize(const std::string §ion, + std::vector<std::string> headers, + bool includeHeaders, + unsigned int startOffset, + unsigned int length, + bool mime) const +{ + if (section == "") { + if (!parseHeaders()) + return 0; + } else if (!parseFull()) + return 0; + + const MimePart *part = doc->getPart(section, "", mime ? MimePart::FetchMime + : MimePart::FetchHeader); + if (!part) { + storage = ""; + return 0; + } + + int fd = getFile(); + if (fd == -1) + return 0; + + storage = ""; + part->printHeader(fd, bincClient, headers, + includeHeaders, startOffset, + length, storage); + + return storage.size(); +} + +//------------------------------------------------------------------------ +bool MaildirMessage::printBody(const std::string §ion, + unsigned int startOffset, + unsigned int length) const +{ + if (!parseFull()) + return false; + + const MimePart *part = doc->getPart(section, ""); + if (!part) { + storage = ""; + return 0; + } + + int fd = getFile(); + if (fd == -1) + return false; + + storage = ""; + part->printBody(fd, bincClient, startOffset, length); + return true; +} + +//------------------------------------------------------------------------ +unsigned int MaildirMessage::getBodySize(const std::string §ion, + unsigned int startOffset, + unsigned int length) const +{ + if (!parseFull()) + return false; + + const MimePart *part = doc->getPart(section, ""); + if (!part) { + storage = ""; + return 0; + } + + if (startOffset > part->bodylength) + return 0; + + unsigned int s = part->bodylength - startOffset; + return s < length ? s : length; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::printDoc(unsigned int startOffset, + unsigned int length, bool onlyText) const +{ + if (!parseFull()) + return false; + + int fd = getFile(); + if (fd == -1) + return false; + + if (onlyText) + startOffset += doc->bodystartoffsetcrlf; + + storage = ""; + doc->printDoc(fd, bincClient, startOffset, length); + return true; +} + +//------------------------------------------------------------------------ +unsigned int MaildirMessage::getDocSize(unsigned int startOffset, + unsigned int length, + bool onlyText) const +{ + if (!parseFull()) + return false; + + unsigned int s = doc->size; + if (onlyText) s -= doc->bodystartoffsetcrlf; + + if (startOffset > s) + return 0; + + s -= startOffset; + return s < length ? s : length; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::headerContains(const std::string &header, + const std::string &text) +{ + if (!parseHeaders()) + return false; + + HeaderItem hitem; + if (!doc->h.getFirstHeader(header, hitem)) + return false; + + string tmp = hitem.getValue(); + uppercase(tmp); + string tmp2 = text; + uppercase(tmp2); + return (tmp.find(tmp2) != string::npos); +} + +//------------------------------------------------------------------------ +bool MaildirMessage::bodyContains(const std::string &text) +{ + if (!parseFull()) + return false; + + // search the body part of the message.. + int fd = getFile(); + if (fd == -1) + return false; + + MimeInputSource mimeSource(fd); + + char c; + for (unsigned int i = 0; i < doc->getBodyStartOffset(); ++i) + if (!mimeSource.getChar(&c)) + break; + + char *ring = new char[text.length()]; + int pos = 0; + int length = doc->getBodyLength(); + const char *textStr = text.c_str(); + unsigned int textLength = text.length(); + while (mimeSource.getChar(&c) && length--) { + ring[pos % textLength] = toupper(c); + + if (compareStringToQueue(textStr, ring, pos + 1, textLength)) { + delete[] ring; + return true; + } + + ++pos; + } + + delete[] ring; + return false; +} + +//------------------------------------------------------------------------ +bool MaildirMessage::textContains(const std::string &text) +{ + // search the body part of the message.. + int fd = getFile(); + if (fd == -1) + return false; + + MimeInputSource mimeSource(fd); + + char c; + char *ring = new char[text.length()]; + int pos = 0; + const char *textStr = text.c_str(); + unsigned int textLength = text.length(); + while (mimeSource.getChar(&c)) { + ring[pos % textLength] = toupper(c); + + if (compareStringToQueue(textStr, ring, pos + 1, textLength)) { + delete[] ring; + return true; + } + + ++pos; + } + + delete[] ring; + return false; +} + +//------------------------------------------------------------------------ +const std::string &MaildirMessage::getHeader(const std::string &header) +{ + static string NIL = ""; + + if (!parseHeaders()) + return NIL; + + HeaderItem hitem; + if (!doc->h.getFirstHeader(header, hitem)) + return NIL; + + return hitem.getValue(); +} + +//------------------------------------------------------------------------ +MaildirMessageCache::MaildirMessageCache(void) +{ +} + +//------------------------------------------------------------------------ +MaildirMessageCache::~MaildirMessageCache(void) +{ + clear(); +} + +//------------------------------------------------------------------------ +MaildirMessageCache &MaildirMessageCache::getInstance(void) +{ + static MaildirMessageCache cache; + return cache; +} + +//------------------------------------------------------------------------ +void MaildirMessageCache::addStatus(const MaildirMessage *m, + ParseStatus s) +{ + if (statuses.find(m) == statuses.end()) { + // Insert status. Perhaps remove oldest status. + if (statuses.size() > 2) { + MaildirMessage *message = const_cast<MaildirMessage *>(parsed.front()); + + removeStatus(message); + } + + parsed.push_back(m); + } + + statuses[m] = s; +} + +//------------------------------------------------------------------------ +MaildirMessageCache::ParseStatus +MaildirMessageCache::getStatus(const MaildirMessage *m) const +{ + if (statuses.find(m) == statuses.end()) + return NotParsed; + + return statuses[m]; +} + +//------------------------------------------------------------------------ +void MaildirMessageCache::clear(void) +{ + for (deque<const MaildirMessage *>::iterator i = parsed.begin(); + i != parsed.end(); ++i) + const_cast<MaildirMessage *>(*i)->close(); + + parsed.clear(); + statuses.clear(); +} + +//------------------------------------------------------------------------ +void MaildirMessageCache::removeStatus(const MaildirMessage *m) +{ + if (statuses.find(m) == statuses.end()) + return; + + statuses.erase(statuses.find(m)); + + for (deque<const MaildirMessage *>::iterator i = parsed.begin(); + i != parsed.end(); ++i) { + if (*i == m) { + const_cast<MaildirMessage *>(*i)->close(); + parsed.erase(i); + break; + } + } +} + +//------------------------------------------------------------------------ +void MaildirMessage::setInternalFlag(unsigned char f) +{ + internalFlags |= f; +} + +//------------------------------------------------------------------------ +unsigned char MaildirMessage::getInternalFlags(void) const +{ + return internalFlags; +} + +//------------------------------------------------------------------------ +void MaildirMessage::clearInternalFlag(unsigned char f) +{ + internalFlags &= ~f; +} + +//------------------------------------------------------------------------ +void MaildirMessage::setCustomFlag(const string &flag) +{ + if (!customFlags) { + internalFlags |= FlagsChanged | CustomFlagsChanged; + customFlags = new vector<string>; + } + + for (vector<string>::const_iterator it = customFlags->begin(); + it != customFlags->end(); ++it) { + if (*it == flag) + return; + } + + internalFlags |= FlagsChanged | CustomFlagsChanged; + customFlags->push_back(flag); +} + +//------------------------------------------------------------------------ +void MaildirMessage::removeCustomFlag(const string &flag) +{ + internalFlags |= FlagsChanged | CustomFlagsChanged; + + if (!customFlags) + return; + + for (vector<string>::iterator it = customFlags->begin(); + it != customFlags->end(); ++it) { + if (*it == flag) { + customFlags->erase(it); + return; + } + } +} + +//------------------------------------------------------------------------ +void MaildirMessage::resetCustomFlags(void) +{ + internalFlags |= FlagsChanged | CustomFlagsChanged; + + delete customFlags; + customFlags = 0; +} + +//------------------------------------------------------------------------ +vector<string> MaildirMessage::getCustomFlags(void) const +{ + if (!customFlags) + return vector<string>(); + + return *customFlags; +} |