void mail::maildir::genericGetMessageFdStruct(string uid, size_t messageNumber, bool peek, int &fdRet, struct rfc2045 *&structret, mail::callback &callback) { if (uid == cacheUID && cachefd >= 0 && cacheRfcp != 0) { fdRet=cachefd; structret=cacheRfcp; callback.success("OK"); return; } if (!fixMessageNumber(this, uid, messageNumber)) { callback.fail("Message removed on the server"); return; } if (cacheRfcp) { rfc2045_free(cacheRfcp); cacheRfcp=NULL; } if (cachefd >= 0) { close(cachefd); cachefd= -1; } if (!fixMessageNumber(this, uid, messageNumber)) { callback.fail("Message removed on the server"); return; } string messageFn=getfilename(messageNumber); if (messageFn.size() == 0) { callback.fail("Message removed on the server"); return; } int fd=maildir_safeopen(messageFn.c_str(), O_RDONLY, 0); struct rfc2045 *rfcp; if (fd < 0 || fcntl(fd, F_SETFD, FD_CLOEXEC) < 0 || (rfcp=rfc2045_alloc()) == NULL) { if (fd >= 0) close(fd); callback.fail("Message removed on the server"); return; } fcntl(fd, F_SETFD, FD_CLOEXEC); cachefd=fd; cacheRfcp=rfcp; cacheUID=""; vector<char> buffer; buffer.insert(buffer.end(), BUFSIZ, 0); int n; while ((n=read(fd, &buffer[0], buffer.size())) > 0) rfc2045_parse(rfcp, &buffer[0], n); rfc2045_parse_partial(rfcp); if (n < 0) { callback.fail(strerror(errno)); return; } fdRet=cachefd; structret=cacheRfcp; if (!peek && index[messageNumber].unread) { index[messageNumber].unread=false; saveFolderIndexInfo(messageNumber, index[messageNumber], callback); return; } callback.success("OK"); }
void mail::maildir::open(string pathStr, mail::callback &callback, mail::callback::folder &folderCallbackArg) { index.clear(); updateNotify(false); folderCallback=NULL; if (cacheRfcp) { rfc2045_free(cacheRfcp); cacheRfcp=NULL; } if (cachefd >= 0) { close(cachefd); cachefd=-1; } if (path == "") { callback.fail(strerror(errno)); return; } set<string> recentMessages; string md; char *d=maildir_name2dir(path.c_str(), pathStr.c_str()); if (!d) { callback.fail(strerror(errno)); return; } try { md=d; free(d); } catch (...) { free(d); LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } { struct stat stat_buf; string d=md + "/" KEYWORDDIR; /* New Courier-IMAP maildirwatch code */ mkdir(d.c_str(), 0700); if (stat(md.c_str(), &stat_buf) == 0) chmod(d.c_str(), stat_buf.st_mode & 0777); } maildir_purgetmp(md.c_str()); maildir_getnew(md.c_str(), NULL, &recent_callback_func, &recentMessages); scan(pathStr, index); folderCallback= &folderCallbackArg; folderPath=pathStr; vector<maildirMessageInfo>::iterator b=index.begin(), e=index.end(); while (b != e) { b->recent=recentMessages.count(b->lastKnownFilename) > 0; b++; } if (lockFolder) maildirwatch_free(lockFolder); lockFolder=maildirwatch_alloc(md.c_str()); readKeywordHelper rkh(this); bool rc; while (rkh.go(md, rc)) ; callback.success("Mail folder opened"); }
void mail::mbox::folder::renameFolder(const mail::folder *newParent, std::string newName, mail::callback::folderList &callback1, mail::callback &callback) const { if (isDestroyed(callback)) return; if (path == "INBOX") { callback.fail("Not implemented."); return; } if (mboxAccount.currentFolder.size() > 0) { if (mboxAccount.currentFolder == path || (path + "/") == mboxAccount.currentFolder.substr(0, path.size()+1)) { callback.fail("Cannot RENAME currently open folder."); return; } } // The name of the folder is translated from the local charset // to modified UTF-7 (Courier-IMAP compatibility), with the following // blacklisted characters: string nameutf7=mail::iconvert::convert(newName, unicode_default_chset(), unicode_x_imap_modutf7 " ./~:"); string newpath=(newParent ? newParent->getPath() + "/": string("")) + nameutf7; if (newpath.size() == 0 || newpath[0] != '/') newpath=mboxAccount.rootPath + "/" + newpath; struct stat stat_buf; if (stat(path.c_str(), &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) { if (rename(path.c_str(), newpath.c_str()) < 0) { callback.fail(strerror(errno)); return; } mail::mbox::folder newFolder(newpath, mboxAccount); vector<const mail::folder *> folders; folders.push_back(&newFolder); callback1.success( folders ); callback.success("Mail folder renamed."); return; } mboxAccount.installTask(new mail::mbox::RenameTask(mboxAccount, callback1, callback, path, newpath, newName)); }
void mail::maildir::folder::renameFolder(const mail::folder *newParent, std::string newName, mail::callback::folderList &callback1, mail::callback &callback2) const { if (isDestroyed(callback2)) return; if (maildirAccount->folderPath.size() > 0) { size_t l=path.size(); if (strncmp(maildirAccount->folderPath.c_str(), path.c_str(), l) == 0 && ((maildirAccount->folderPath.c_str())[l] == 0 || (maildirAccount->folderPath.c_str())[l] == '.')) { callback2.fail("Cannot RENAME currently open folder."); return; } } // The name of the folder is translated from the local charset // to modified UTF-7 (Courier-IMAP compatibility), with the following // blacklisted characters: char *s=libmail_u_convert_tobuf(newName.c_str(), unicode_default_chset(), unicode_x_imap_modutf7 " ./~:", NULL); if (!s) { callback2.fail(strerror(errno)); return; } std::string nameutf7; errno=ENOMEM; try { nameutf7=s; free(s); } catch (...) { free(s); callback2.fail(strerror(errno)); return; } mail::maildir::folder newFolder(maildirAccount, (newParent ? newParent->getPath() + ".": string("")) + nameutf7); newFolder.hasMessages( hasMessages() ); newFolder.hasSubFolders( hasSubFolders() ); vector<const mail::folder *> folders; // Paths are INBOX.foo string from, to; char *p=maildir_name2dir(".", path.c_str()); if (p) try { from=p+2; // Skip ./ free(p); } catch (...) { free(p); LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } p=maildir_name2dir(".", newFolder.path.c_str()); if (p) try { to=p+2; // Skip ./ free(p); } catch (...) { free(p); LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } if (from.size() > 0 && to.size() > 0 && maildir_rename(maildirAccount->path.c_str(), from.c_str(), to.c_str(), MAILDIR_RENAME_FOLDER | MAILDIR_RENAME_SUBFOLDERS, NULL)) { callback2.fail(strerror(errno)); } else { folders.push_back(&newFolder); callback1.success( folders ); callback2.success("Mail folder renamed"); } }
void mail::mbox::folder::destroy(mail::callback &callback, bool destroyDir) const { if (destroyDir) { // Clean up garbage first. DIR *dirp=opendir(path.c_str()); try { struct dirent *de; while (dirp && (de=readdir(dirp)) != NULL) { const char *p=strrchr(de->d_name, '~'); if (p && p[1] == 0) // Temp file? { string s=path + "/" + string((const char *) de->d_name, p); struct stat stat_buf; if (stat(s.c_str(), &stat_buf) < 0) { s += "~"; unlink(s.c_str()); } continue; } for (p=de->d_name; *p; p++) { if (strncmp(p, ".lock.", 6) == 0) { string s=path + "/" + de->d_name; struct stat stat_buf; if (stat(s.c_str(), &stat_buf) == 0 && stat_buf.st_mtime + 120 < time(NULL)) break; } if (strcmp(p, ".lock") == 0) { string s=path + "/" + string((const char *) de->d_name, p); struct stat stat_buf; if (stat(s.c_str(), &stat_buf) < 0) break; } } if (*p) { string s=path + "/" + de->d_name; unlink(s.c_str()); } } if (dirp) closedir(dirp); } catch (...) { if (dirp) closedir(dirp); LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } if (rmdir(path.c_str()) < 0) { callback.fail(path + ": " + strerror(errno)); return; } } else { if (unlink(path.c_str()) < 0) { callback.fail(path + ": " + strerror(errno)); return; } } callback.success("OK"); }