--- src/depot.cc 31 Aug 2003 11:16:26 -0000 1.3 +++ src/depot.cc 14 Sep 2003 08:21:28 -0000 1.4 @@ -299,8 +299,6 @@ //-------------------------------------------------------------------- bool Depot::getStatus(const std::string &s_in, Status &dest) const { - IO &logger = IOFactory::getInstance().get(2); - const string mailbox = toCanonMailbox(s_in); Mailbox *m = get(mailbox); if (m == 0) { @@ -310,26 +308,16 @@ int statusid = m->getStatusID(mailboxToFilename(mailbox)); if (mailboxstatuses.find(mailbox) != mailboxstatuses.end()) { - logger << "Depot::getStatus(\"" << s_in << "\") found in cache" << endl; - dest = mailboxstatuses[mailbox]; - - if (dest.getStatusID() == statusid) { - logger << "Depot::getStatus(\"" << s_in << "\") mailbox unchanged" << endl; + if (dest.getStatusID() == statusid) return true; - } } - logger << "Depot::getStatus(\"" << s_in << "\") finding status" << endl; - if (!m->getStatus(mailboxToFilename(mailbox), dest)) { setLastError(m->getLastError()); - - logger << "Depot::getStatus(\"" << s_in << "\") failed!" << endl; return false; } - logger << "Depot::getStatus(\"" << s_in << "\") success!" << endl; dest.setStatusID(statusid); mailboxstatuses[mailbox] = dest; return true; @@ -338,14 +326,84 @@ //-------------------------------------------------------------------- Depot::iterator::iterator(void) { + IO &logger = IOFactory::getInstance().get(2); + logger << "iterator() ref = 1" << endl; + dirp = 0; + ref = new int; + *ref = 1; } //-------------------------------------------------------------------- Depot::iterator::iterator(DIR *dp, struct dirent *sp) { + IO &logger = IOFactory::getInstance().get(2); + logger << "iterator() ref = 1" << endl; + dirp = dp; direntp = sp; + + ref = new int; + *ref = 1; +} + +//-------------------------------------------------------------------- +Depot::iterator::iterator(const iterator ©) +{ + IO &logger = IOFactory::getInstance().get(2); + logger << "iterator(const iterator ©) ref = " << endl; + + if (*copy.ref != 0) + ++(*copy.ref); + + ref = copy.ref; + dirp = copy.dirp; + direntp = copy.direntp; +} + +//-------------------------------------------------------------------- +Depot::iterator::~iterator(void) +{ + IO &logger = IOFactory::getInstance().get(2); + logger << "~iterator(), ref = " << endl; + + deref(); +} + +//-------------------------------------------------------------------- +Depot::iterator &Depot::iterator::operator =(const iterator ©) +{ + IO &logger = IOFactory::getInstance().get(2); + logger << "iterator = (const iterator ©)" << endl; + + if (*copy.ref != 0) + ++(*copy.ref); + + deref(); + + ref = copy.ref; + dirp = copy.dirp; + direntp = copy.direntp; + + return *this; +} + +//-------------------------------------------------------------------- +void Depot::iterator::deref(void) +{ + IO &logger = IOFactory::getInstance().get(2); + logger << "deref()" << endl; + + // decrease existing copy ref if there is one + if (*ref != 0 && --(*ref) == 0) { + if (dirp) { + closedir(dirp); + dirp = 0; + } + + delete ref; + ref = 0; + } } //-------------------------------------------------------------------- --- src/depot.h 18 Aug 2003 18:06:05 -0000 1.1.1.1 +++ src/depot.h 14 Sep 2003 08:21:28 -0000 1.2 @@ -64,9 +64,6 @@ public: //-- class iterator { - DIR *dirp; - struct dirent *direntp; - public: std::string operator * (void) const; void operator ++ (void); @@ -74,9 +71,20 @@ bool operator == (iterator) const; iterator(void); + iterator(const iterator ©); iterator(DIR *, struct dirent *); + ~iterator(void); + + void deref(void); + + iterator &operator =(const iterator ©); friend class Depot; + + private: + DIR *dirp; + struct dirent *direntp; + int *ref; }; private: --- src/io-ssl.cc 18 Aug 2003 18:06:05 -0000 1.1.1.1 +++ src/io-ssl.cc 14 Sep 2003 08:21:28 -0000 1.2 @@ -259,7 +259,7 @@ int r = select(fileno(stdin) + 1, &rfds, 0, 0, timeout); if (r == 0) { setLastError("Reading from client timed out."); - return -1; + return -2; } if (r < 0) { @@ -290,12 +290,7 @@ return -1; } - if (timeout == 0) { - setLastError("Reading from client timed out."); - return -1; - } - - if (!retry) { + if (timeout == 0 || !retry) { setLastError("Reading from client timed out."); return -2; } --- src/io.cc 28 Aug 2003 20:02:21 -0000 1.2 +++ src/io.cc 14 Sep 2003 08:21:28 -0000 1.3 @@ -304,7 +304,7 @@ int r = select(fileno(stdin) + 1, &rfds, 0, 0, timeout); if (r == 0) { setLastError("Client timed out"); - return -1; + return -2; } else if (r == -1) { setLastError("Error reading from client"); return -1; --- src/mime-parsefull.cc 9 Sep 2003 18:27:29 -0000 1.5 +++ src/mime-parsefull.cc 14 Sep 2003 08:21:28 -0000 1.7 @@ -143,11 +143,11 @@ headerstartoffsetcrlf = crlfoffset; - while (!quit) { + while (!quit && !eof) { // read name while (1) { if (!crlfGetChar(c)) { - quit = true; + eof = true; break; } @@ -175,7 +175,7 @@ break; } - if (quit) break; + if (quit || eof) break; while (!quit) { if (!crlfGetChar(c)) { @@ -303,16 +303,16 @@ // boundary. then we call parse() for all parts. the last parse() // command will return a code indicating that it found the last // boundary of this multipart. - string _boundary = "\r\n--"; _boundary += boundary; + string delimiter = "\r\n--" + boundary; - char *boundaryqueue = 0; - int endpos = _boundary.length(); - boundaryqueue = new char[endpos]; - int boundarypos = 0; + char *delimiterqueue = 0; + int endpos = delimiter.length(); + delimiterqueue = new char[endpos]; + int delimiterpos = 0; bool eof = false; - // first, skip to the first boundary string. Anything between the - // header and the first boundary string is simply ignored (it's + // first, skip to the first delimiter string. Anything between the + // header and the first delimiter string is simply ignored (it's // usually a text message intended for non-mime clients) do { if (!crlfGetChar(c)) { @@ -323,12 +323,12 @@ if (c == '\n') ++nlines; - boundaryqueue[boundarypos++ % endpos] = c; + delimiterqueue[delimiterpos++ % endpos] = c; - // Fixme: Must also check for all parents' boundary. - } while (!compareStringToQueue(_boundary, boundaryqueue, boundarypos, endpos)); + // Fixme: Must also check for all parents' delimiter. + } while (!compareStringToQueue(delimiter, delimiterqueue, delimiterpos, endpos)); - delete boundaryqueue; + delete delimiterqueue; // Read two more characters. This may be CRLF, it may be "--" and // it may be any other two characters. --- src/operator-list.cc 18 Aug 2003 18:06:05 -0000 1.1.1.1 +++ src/operator-list.cc 14 Sep 2003 08:21:28 -0000 1.2 @@ -182,19 +182,18 @@ int flags = i->second; bool noselect = false; - /* + if (!(flags & DIR_SELECT)) { com << sep << "\\Noselect"; - sep = " "; + sep = " "; noselect = true; } - */ if (!noselect) { if (flags & DIR_MARKED) com << sep << "\\Marked"; else - com << sep << "\\UnMarked"; + com << sep << "\\Unmarked"; sep = " "; } --- src/operator-lsub.cc 10 Sep 2003 20:56:45 -0000 1.3 +++ src/operator-lsub.cc 14 Sep 2003 08:21:28 -0000 1.4 @@ -88,7 +88,6 @@ { Session &session = Session::getInstance(); IO &com = IOFactory::getInstance().get(1); - IO &logger = IOFactory::getInstance().get(2); const char delim = depot.getDelimiter(); // remove leading or trailing delimiter in wildcard @@ -100,10 +99,11 @@ // remove leading or trailing delimiter in reference string ref = command.getMailbox(); - trim(ref, string(&delim, 1)); + while (ref.length() > 1 && ref[0] == depot.getDelimiter()) + ref = ref.substr(1); - // a map from mailbox name to flags - map mailboxes; + // a multimap from mailbox name to flags + multimap mailboxes; // read through all entries in depository. for (Depot::iterator i = depot.begin("."); i != depot.end(); ++i) { @@ -121,13 +121,8 @@ trim(tmp, string(&delim, 1)); if (tmp == "") continue; - else { - // inherit flags that were already set for this mailbox. - int flags = DIR_SELECT; - if (m->isMarked(path)) flags |= DIR_MARKED; - if (mailboxes.find(tmp) != mailboxes.end()) flags |= mailboxes[tmp]; - mailboxes[tmp] = flags; - } + else + mailboxes.insert(make_pair(tmp, DIR_SELECT)); // now add all superior mailboxes with no flags set if not // added already. @@ -136,8 +131,9 @@ tmp = tmp.substr(0, pos); trim(tmp, string(&delim, 1)); - if (mailboxes.find(tmp) == mailboxes.end()) - mailboxes[tmp] = 0; + multimap::iterator mi = mailboxes.find(tmp); + if (mi == mailboxes.end()) + mailboxes.insert(make_pair(tmp, 0)); pos = tmp.rfind(delim); } @@ -164,91 +160,52 @@ } } - // load subscription list - Storage subs; - if (!subs.load("bincimap-subscribed")) { - session.globalconfig.setSection("Mailbox"); - string autosubmailboxes = session.globalconfig["auto subscribe mailboxes"]; - vector mboxes; - split(autosubmailboxes, ",", mboxes); - - Storage subs; - subs.setSection("subscribed"); - int n = 0; - for (vector::const_iterator i = mboxes.begin(); i != mboxes.end(); - ++i) { - string tmp = *i; - trim(tmp); - subs.insert(toString(n), tmp); - session.subscribed.push_back(tmp); - ++n; - } - - if (!subs.save("bincimap-subscribed")) - logger << subs.getLastError() << endl; - - } else { - subs.setSection("subscribed"); - - string folder; - string key; - if (subs.getFirstEntry(key, folder)) - do { - session.subscribed.push_back(folder); - } while (subs.getNextEntry(key, folder)); - } + session.loadSubscribes(); vector &subscribed = session.subscribed; sort(subscribed.begin(), subscribed.end()); + // finally, print all mailbox entries with flags. for (vector::const_iterator j = subscribed.begin(); - j != subscribed.end(); ++j) - if (mailboxes.find(*j) == mailboxes.end()) - mailboxes[*j] = 0; + j != subscribed.end(); ++j) { + if (ref != "" && (ref.length() > (*j).length() + || ((*j).substr(0, ref.length()) != ref))) + continue; - // finally, print all mailbox entries with flags. - for (i = mailboxes.begin(); i != mailboxes.end(); ++i) { - if (ref == "" || ((ref.length() <= i->first.length()) - && (i->first.substr(0, ref.length()) == ref))) - if (regexMatch(i->first, regex) == 0) { - bool match = false; - for (vector::const_iterator j = subscribed.begin(); - j != subscribed.end(); ++j) - if (*j == i->first) { - match = true; - break; - } - - if (!match) { - // can never happen - continue; - } - - com << "* LSUB ("; - int flags = i->second; - string sep = ""; - - bool noselect = false; - // if (!(flags & DIR_SELECT)) { - // com << sep << "\\Noselect"; - // sep = " "; - // noselect = true; - // } - - if (!noselect) { - if (flags & DIR_MARKED) - com << sep << "\\Marked"; - else - com << sep << "\\UnMarked"; - sep = " "; - } + if (regexMatch((*j).substr(ref.length()), regex) != 0) + continue; - if (flags & DIR_NOINFERIORS) - com << sep << "\\Noinferiors"; + int flags = 0; - com << ") \"" << depot.getDelimiter() << "\" " - << toImapString(i->first) << endl; + for (i = mailboxes.begin(); i != mailboxes.end(); ++i) + if (i->first == *j) { + flags = i->second; + break; } + + com << "* LSUB ("; + string sep = ""; + + bool noselect = false; + if (!(flags & DIR_SELECT)) { + com << sep << "\\Noselect"; + sep = " "; + noselect = true; + } + + if (!noselect) { + if (flags & DIR_MARKED) + com << sep << "\\Marked"; + else + com << sep << "\\Unmarked"; + sep = " "; + } + + if (flags & DIR_NOINFERIORS) + com << sep << "\\Noinferiors"; + + com << ") \"" << depot.getDelimiter() << "\" " + << toImapString(*j) << endl; } return OK; --- src/operator-subscribe.cc 18 Aug 2003 18:06:05 -0000 1.1.1.1 +++ src/operator-subscribe.cc 14 Sep 2003 08:21:28 -0000 1.2 @@ -85,19 +85,9 @@ const string &srcmailbox = command.getMailbox(); const string &canonmailbox = toCanonMailbox(srcmailbox); - session.subscribed.push_back(canonmailbox); - - Storage subs; - subs.setSection("subscribed"); - int n = 0; - for (vector::const_iterator i = session.subscribed.begin(); - i != session.subscribed.end(); ++i) { - subs.insert(toString(n), *i); - ++n; - } - - if (!subs.save("bincimap-subscribed")) - logger << "Saving bincimap-subscribed failed: " << subs.getLastError(); + session.loadSubscribes(); + session.subscribeTo(canonmailbox); + session.saveSubscribes(); return OK; } --- src/operator-unsubscribe.cc 18 Aug 2003 18:06:05 -0000 1.1.1.1 +++ src/operator-unsubscribe.cc 14 Sep 2003 08:21:28 -0000 1.2 @@ -85,29 +85,15 @@ const string &mailbox = command.getMailbox(); const string &canonmailbox = toCanonMailbox(mailbox); - for (vector::iterator i = session.subscribed.begin(); - i != session.subscribed.end(); ++i) - if (*i == canonmailbox) { - session.subscribed.erase(i); + session.loadSubscribes(); + if (!session.unsubscribeTo(canonmailbox)) { + session.setLastError("Not subscribed to " + toImapString(mailbox)); + return NO; + } - Storage subs; - subs.setSection("subscribed"); - int n = 0; - for (vector::const_iterator i = session.subscribed.begin(); - i != session.subscribed.end(); ++i, ++n) - subs.insert(toString(n), *i); - - if (!subs.save("bincimap-subscribed")) { - // FIXME - // logger << "Saving bincimap-subscribed failed: " - // << e.getReason() << endl; - } + session.saveSubscribes(); - return OK; - } - - session.setLastError("Not subscribed to " + toImapString(mailbox)); - return NO; + return OK; } //---------------------------------------------------------------------- --- src/regmatch.cc 18 Aug 2003 18:06:05 -0000 1.1.1.1 +++ src/regmatch.cc 14 Sep 2003 08:21:28 -0000 1.2 @@ -51,10 +51,7 @@ regmatch_t rm[2]; if (regcomp(&r, p_in.c_str(), REG_EXTENDED | REG_NOSUB) != 0) - { - regfree(&r); // Don't want to leak here. return 2; - } int n = regexec(&r, data_in.c_str(), data_in.length(), rm, 0); regfree(&r); --- src/session-initialize-bincimapd.cc 23 Aug 2003 14:58:54 -0000 1.2 +++ src/session-initialize-bincimapd.cc 14 Sep 2003 08:21:28 -0000 1.3 @@ -246,38 +246,7 @@ } // load subscription list - Storage subs; - if (!subs.load("bincimap-subscribed")) { - session.globalconfig.setSection("Mailbox"); - string autosubmailboxes = session.globalconfig["auto subscribe mailboxes"]; - vector mboxes; - split(autosubmailboxes, ",", mboxes); - - Storage subs; - subs.setSection("subscribed"); - int n = 0; - for (vector::const_iterator i = mboxes.begin(); i != mboxes.end(); - ++i) { - string tmp = *i; - trim(tmp); - subs.insert(toString(n), tmp); - session.subscribed.push_back(tmp); - ++n; - } - - if (!subs.save("bincimap-subscribed")) - logger << subs.getLastError() << endl; - - } else { - subs.setSection("subscribed"); - - string folder; - string key; - if (subs.getFirstEntry(key, folder)) - do { - session.subscribed.push_back(folder); - } while (subs.getNextEntry(key, folder)); - } + session.loadSubscribes(); session.setState(Session::AUTHENTICATED); @@ -304,15 +273,6 @@ // Read timeout settings from global config session.globalconfig.setSection("Session"); - int idletimeout = atoi(session.globalconfig["idle timeout"]); - int authtimeout = atoi(session.globalconfig["auth timeout"]); - int transfertimeout = atoi(session.globalconfig["transfer timeout"]); - - // Settings are not allowed to break the IMAP protocol - if (idletimeout < (30 * 60)) idletimeout = 30 * 60; - - // No auth timeout is not allowed. - if (authtimeout < 30) authtimeout = 30; // Set transfer timeout com.setTransferTimeout(transfertimeout); --- src/session.cc 23 Aug 2003 14:58:54 -0000 1.2 +++ src/session.cc 14 Sep 2003 08:21:28 -0000 1.3 @@ -379,7 +379,7 @@ } //---------------------------------------------------------------------- -void Session::setLastError(const string &error) +void Session::setLastError(const string &error) const { lastError = error; } @@ -406,4 +406,136 @@ } return hostname; +} + +//---------------------------------------------------------------------- +void Session::subscribeTo(const std::string mailbox) +{ + subscribed.push_back(mailbox); +} + +//---------------------------------------------------------------------- +bool Session::unsubscribeTo(const std::string mailbox) +{ + for (vector::iterator i = subscribed.begin(); + i != subscribed.end(); ++i) { + if (*i == mailbox) { + subscribed.erase(i); + return true; + } + } + + return false; +} + +//---------------------------------------------------------------------- +void Session::loadSubscribes(void) +{ + // drop all existing subscribed folders. + subscribed.clear(); + + // load subscription list. if it doesn't exist - initialize it with + // the values from the auto subscribe list. + Storage subs; + subs.setSection("subscribed"); + + bool ok = false; + FILE *fp = fopen(".bincimap-subscribed", "r"); + if (fp) { + int c; + int n = 0; + string current; + while ((c = fgetc(fp)) != EOF) { + if (c == '\n') { + trim(current); + if (current != "") { + subs.insert(toString(n++), current); + current = ""; + } + } else + current += c; + } + + fclose(fp); + ok = true; + } + + bool deleteOld = false; + if (!ok) { + if ((ok = subs.load("bincimap-subscribed"))) + deleteOld = true; + } + + if (!ok) { + globalconfig.setSection("Mailbox"); + string autosubmailboxes = globalconfig["auto subscribe mailboxes"]; + vector mboxes; + split(autosubmailboxes, ",", mboxes); + + for (vector::const_iterator i = mboxes.begin(); i != mboxes.end(); + ++i) { + string tmp = *i; + trim(tmp); + subscribed.push_back(tmp); + } + + saveSubscribes(); + + } else { + subs.setSection("subscribed"); + + IO &logger = IOFactory::getInstance().get(2); + + string folder; + string key; + if (subs.getFirstEntry(key, folder)) + do { + logger << "Pushing back " << folder << endl; + subscribed.push_back(folder); + } while (subs.getNextEntry(key, folder)); + } + + if (deleteOld) { + if (saveSubscribes()) + unlink("bincimap-subscribed"); + } +} + +//---------------------------------------------------------------------- +bool Session::saveSubscribes(void) const +{ + IO &logger = IOFactory::getInstance().get(2); + + // create a safe file name + string tpl = ".bincimap-subscribed-tmp-XXXXXX"; + char *ftemplate = new char[tpl.length() + 1]; + + strcpy(ftemplate, tpl.c_str()); + int fd = mkstemp(ftemplate); + if (fd == -1) { + logger << "Unable to create temporary file \"" + << tpl << "\"" << endl; + return false; + } + + for (vector::const_iterator i = subscribed.begin(); + i != subscribed.end(); ++i) { + string w = (*i) + "\n"; + if (write(fd, w.c_str(), w.length()) != (ssize_t) w.length()) { + logger << "Failed to write to " << tpl << ": " + << strerror(errno) << endl; + break; + } + } + + fsync(fd); + close(fd); + if (rename(ftemplate, ".bincimap-subscribed") != 0) { + logger << "Failed to rename " << ftemplate + << " to .bincimap-subscribed: " + << strerror(errno) << endl; + return false; + } + + return true; } --- src/session.h 23 Aug 2003 14:58:54 -0000 1.2 +++ src/session.h 14 Sep 2003 08:21:28 -0000 1.3 @@ -48,30 +48,6 @@ //-------------------------------------------------------------------- class Session { - //-- - int state; - std::string userid; - std::string ip; - char **argv; - int argc; - - int logfacility; - - int readbytes; - int writebytes; - int statements; - int bodies; - - Depot *depot; - - std::string lastError; - ArgParser::Args args; - - pid_t pid; - std::string hostname; - - Session(void); - public: std::map attrs; @@ -97,8 +73,13 @@ Storage globalconfig; Storage localconfig; + std::vector subscribed; - + void subscribeTo(const std::string mailbox); + bool unsubscribeTo(const std::string mailbox); + void loadSubscribes(void); + bool saveSubscribes(void) const; + const int getState(void) const; void setState(int n); void exportToEnv(void); @@ -120,7 +101,7 @@ const std::string &getUserID() const; pid_t getPid(void); const std::string &getHostname(void); - void setLastError(const std::string &error); + void setLastError(const std::string &error) const; void setIP(const std::string &ip); void setUserID(const std::string &s); @@ -137,6 +118,30 @@ bool initialize(int argc, char *argv[]); + private: + //-- + int state; + std::string userid; + std::string ip; + char **argv; + int argc; + + int logfacility; + + int readbytes; + int writebytes; + int statements; + int bodies; + + Depot *depot; + + mutable std::string lastError; + ArgParser::Args args; + + pid_t pid; + std::string hostname; + + Session(void); }; inline Depot *Session::getDepot(void) const