void mail::maildir::saveFolderIndexInfo(size_t msgNum, const mail::messageInfo &info, mail::callback &callback) { if (msgNum >= index.size()) { callback.success("OK"); return; } mail::messageInfo &newFlags=index[msgNum]; #define DOFLAG(dummy, field, dummy2) \ newFlags.field=info.field; LIBMAIL_MSGFLAGS; #undef DOFLAG string errmsg="Message updated"; if (!updateFlags(msgNum)) errmsg="Folder opened in read-only mode."; callback.success(errmsg); }
void mail::maildir::folder::readFolderInfo( mail::callback::folderInfo &callback1, mail::callback &callback2) const { if (isDestroyed(callback2)) return; callback1.messageCount=0; callback1.unreadCount=0; vector<maildirMessageInfo> dummyIndex; if (!maildirAccount->scan(path, dummyIndex, true)) { callback1.success(); callback2.fail("Invalid folder"); return; } vector<maildirMessageInfo>::iterator b=dummyIndex.begin(), e=dummyIndex.end(); while (b != e) { callback1.messageCount++; if ( b->unread) callback1.unreadCount++; b++; } callback1.success(); callback2.success("OK"); }
void mail::addressbook::getEntry( string uid, vector<T> &addrListArg, mail::callback &callback) { size_t n=index.size(); size_t i; for (i=0; i<n; i++) if (server->getFolderIndexInfo(i).uid == uid) { GetAddressList<T> *get= new GetAddressList<T>(this, i, addrListArg, callback); if (!get) { callback.fail(strerror(errno)); return; } try { get->go(); } catch (...) { delete get; LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } return; } callback.success("NOT FOUND."); }
void mail::mbox::saveFolderIndexInfo(size_t messageNum, const mail::messageInfo &info, mail::callback &callback) { MONITOR(mail::mbox); if (messageNum < index.size()) { folderDirty=true; #define DOFLAG(dummy1, field, dummy2) \ (index[messageNum].field= info.field) LIBMAIL_MSGFLAGS; #undef DOFLAG } callback.success(currentFolderReadOnly ? "Folder opened in read-only mode.": "Message updated."); if (! DESTROYED() && messageNum < index.size() && currentFolderCallback) currentFolderCallback->messageChanged(messageNum); }
void mail::mbox::findFolder(string path, mail::callback::folderList &callback1, mail::callback &callback2) { if (path.size() == 0) path=rootPath; else if (path[0] != '/' && path != "INBOX") path=rootPath + "/" + path; folder *f=new folder(path, *this); if (!f) { callback2.fail(path + ": " + strerror(errno)); return; } try { vector<const mail::folder *> folder_list; folder_list.push_back(f); callback1.success(folder_list); callback2.success("OK"); delete f; } catch (...) { delete f; LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } }
void mail::maildir::folder::destroy(mail::callback &callback, bool destroyDir) const { if (isDestroyed(callback)) return; if (!destroyDir) // Folder directories are imaginary, cannot be nuked { string s; char *d=maildir_name2dir(maildirAccount->path.c_str(), path.c_str()); if (!d) { callback.fail(strerror(errno)); return; } try { s=d; free(d); } catch (...) { free(d); LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } if (!mail::maildir::maildirdestroy(s)) { callback.fail(strerror(errno)); return; } } callback.success("Mail folder deleted"); }
void mail::imap::findFolder(string folder, mail::callback::folderList &callback1, mail::callback &callback2) { if (!ready(callback2)) return; if (folder.size() == 0) // Top level hierarchy { mail::imapFolder f(*this, "", "", "", -1); f.hasMessages(false); f.hasSubFolders(true); vector<const mail::folder *> list; list.push_back(&f); callback1.success(list); callback2.success("OK"); return; } installForegroundTask( smap ? (imapHandler *) new mail::smapLISToneFolder(folder, callback1, callback2) : new mail::imapListHandler(callback1, callback2, folder_chset(), folder, true)); }
mail::maildir::maildir(mail::callback::disconnect &disconnect_callback, mail::callback &callback, string pathArg) : mail::account(disconnect_callback), CONSTRUCTOR { if (init(callback, pathArg)) callback.success("Mail folders opened"); }
void mail::maildir::updateNotify(bool enableDisable, mail::callback &callback) { updateNotify(enableDisable); if (!enableDisable) updateFolderIndexInfo(&callback, false); else callback.success("OK"); }
void mail::mbox::updateFolderIndexInfo(mail::callback &callback) { if (currentFolder.size() == 0) { callback.success("Mail folder updated"); return; } installTask(new ExpungeTask(*this, callback, true, NULL)); }
void mail::maildir::logout(mail::callback &callback) { updateNotify(false); if (!calledDisconnected) { calledDisconnected=true; disconnect_callback.disconnected(""); } callback.success("OK"); }
void mail::mbox::logout(mail::callback &callback) { if (!folderDirty) { callback.success("Mail folder closed."); return; } // Something dirty needs to be saved. installTask(new ExpungeTask(*this, callback, false, NULL)); }
void mail::maildir::folder::create(bool isDirectory, mail::callback &callback) const { if (!doCreate(isDirectory)) { callback.fail(strerror(errno)); } else { callback.success("Mail folder created"); } }
void mail::maildir::findFolder(string folder, mail::callback::folderList &callback1, mail::callback &callback2) { mail::maildir::folder tempFolder(this, folder); vector<const mail::folder *> folderList; folderList.push_back(&tempFolder); callback1.success(folderList); callback2.success("OK"); }
void mail::imapFolder::readFolderInfo(mail::callback::folderInfo &callback1, mail::callback &callback2) const { if (isDestroyed(callback2)) return; if (imapAccount.currentFolder && imapAccount.currentFolder->path == path) { imapFOLDERinfo *f=imapAccount.currentFolder; vector<imapFOLDERinfo::indexInfo>::iterator b, e; b=f->index.begin(); e=f->index.end(); callback1.messageCount=f->index.size(); callback1.unreadCount=0; while (b != e) { if (b->unread) ++callback1.unreadCount; b++; } callback1.success(); callback2.success("OK"); return; } if (!imapAccount.smap && callback1.fastInfo && !imapAccount.hasCapability(LIBMAIL_CHEAPSTATUS)) { callback2.success("OK"); return; } imapAccount.folderStatus(path, callback1, callback2); }
void mail::maildir::folder::createSubFolder(string name, bool isDirectory, mail::callback::folderList &callback1, mail::callback &callback2) const { if (isDestroyed(callback2)) 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 *p=libmail_u_convert_tobuf(name.c_str(), unicode_default_chset(), unicode_x_imap_modutf7 " ./~:", NULL); if (!p) { callback2.fail(strerror(errno)); return; } std::string nameutf7; errno=ENOMEM; try { nameutf7=p; free(p); } catch (...) { free(p); callback2.fail(strerror(errno)); return; } mail::maildir::folder newFolder(maildirAccount, path + "." + nameutf7); newFolder.hasMessagesFlag= ! (newFolder.hasSubfoldersFlag= isDirectory); if (!newFolder.doCreate(isDirectory)) { callback2.fail(strerror(errno)); return; } vector<const mail::folder *> folders; folders.push_back(&newFolder); callback1.success( folders ); callback2.success("Mail folder created"); }
void mail::mbox::updateFolderIndexFlags(const vector<size_t> &messages, bool doFlip, bool enableDisable, const mail::messageInfo &flags, mail::callback &callback) { vector<size_t>::const_iterator b, e; b=messages.begin(); e=messages.end(); size_t n=index.size(); while (b != e) { size_t i= *b++; if (i < n) { #define DOFLAG(dummy, field, dummy2) \ if (flags.field) \ { \ index[i].field=\ doFlip ? !index[i].field\ : enableDisable; \ } LIBMAIL_MSGFLAGS; #undef DOFLAG } } folderDirty=true; b=messages.begin(); e=messages.end(); MONITOR(mail::mbox); while (!DESTROYED() && b != e) { size_t i= *b++; if (i < n && currentFolderCallback) currentFolderCallback->messageChanged(i); } callback.success(!DESTROYED() && currentFolderReadOnly ? "Folder opened in read-only mode.": "Message updated."); }
void mail::mbox::genericGetMessageStruct(string uid, size_t messageNumber, struct rfc2045 *&structRet, mail::callback &callback) { if (uid == cachedMessageUid && cachedMessageRfcp) { structRet=cachedMessageRfcp; callback.success("OK"); return; } installTask(new GenericGetMessageTask(*this, callback, uid, messageNumber, true, NULL, &structRet)); }
void mail::mbox::folder::createSubFolder(string name, bool isDirectory, mail::callback::folderList &callback1, mail::callback &callback2) const { string fpath; char *p=libmail_u_convert_tobuf(name.c_str(), unicode_default_chset(), unicode_x_imap_modutf7 " ./~:", NULL); if (!p) LIBMAIL_THROW("Out of memory."); try { fpath=path + "/" + p; free(p); } catch (...) { free(p); LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } if (isDirectory) { if (mkdir(fpath.c_str(), 0700) < 0) { callback2.fail(fpath + ": " + strerror(errno)); return; } } else { int fd= ::open(fpath.c_str(), O_RDWR|O_CREAT|O_EXCL, 0600); if (fd < 0) { callback2.fail(fpath + ": " + strerror(errno)); return; } close(fd); } folder newFolder(fpath, mboxAccount); vector<const mail::folder *> folderList; folderList.push_back(&newFolder); callback1.success(folderList); callback2.success("OK"); }
void mail::addressbook::getIndex( list< pair<string, std::string> > &listArg, mail::callback &callback) { size_t n=index.size(); size_t i; for (i=0; i<n; i++) { string nickname=index[i].nickname; string uid=index[i].uid; if (nickname.size() > 0 && uid.size() > 0) listArg.push_back( make_pair(nickname, uid)); } callback.success("Address book index retrieved"); }
void mail::mbox::genericGetMessageFd(string uid, size_t messageNumber, bool peek, int &fdRet, mail::callback &callback) { if (uid == cachedMessageUid && cachedMessageFp) { fdRet=fileno(cachedMessageFp); callback.success("OK"); return; } installTask(new GenericGetMessageTask(*this, callback, uid, messageNumber, peek, &fdRet, NULL)); }
void mail::imap::readTopLevelFolders(mail::callback::folderList &callback1, mail::callback &callback2) { vector<const mail::folder *> folders; vector<mail::imapFolder>::iterator b, e; b=namespaces.begin(); e=namespaces.end(); while (b != e) { folders.push_back(&*b); b++; } callback1.success(folders); callback2.success("OK"); }
void mail::maildir::readTopLevelFolders(mail::callback::folderList &callback1, mail::callback &callback2) { mail::maildir::folder inbox(this, INBOX); mail::maildir::folder folders(this, INBOX); inbox.hasSubfoldersFlag=false; folders.hasMessagesFlag=false; vector<const mail::folder *> folderList; folderList.push_back(&inbox); if (!ispop3maildrop) folderList.push_back(&folders); callback1.success(folderList); callback2.success("OK"); }
void mail::maildir::updateFolderIndexFlags(const vector<size_t> &messages, bool doFlip, bool enableDisable, const mail::messageInfo &flags, mail::callback &callback) { string errmsg="Message updated"; vector<size_t>::const_iterator b, e; b=messages.begin(); e=messages.end(); size_t n=index.size(); MONITOR(mail::maildir); while (!DESTROYED() && b != e) { size_t i= *b++; if (i < n) { #define DOFLAG(dummy, field, dummy2) \ if (flags.field) \ { \ index[i].field=\ doFlip ? !index[i].field\ : enableDisable; \ } LIBMAIL_MSGFLAGS; #undef DOFLAG } if (!updateFlags(i)) errmsg="Folder opened in read-only mode."; } callback.success(errmsg); }
void mail::mbox::folder::readFolderInfo( mail::callback::folderInfo &callback1, mail::callback &callback2) const { if (isDestroyed(callback2)) return; callback1.messageCount=0; callback1.unreadCount=0; if (path.size() == 0) { callback1.success(); callback2.success("OK"); return; } mboxAccount.installTask(new mail::mbox::StatusTask(path, mboxAccount, callback2, callback1)); }
void mail::mbox::genericGetMessageFdStruct(string uid, size_t messageNumber, bool peek, int &fdRet, struct rfc2045 *&structret, mail::callback &callback) { if (uid == cachedMessageUid && cachedMessageRfcp && cachedMessageFp) { structret=cachedMessageRfcp; fdRet=fileno(cachedMessageFp); callback.success("OK"); return; } installTask(new GenericGetMessageTask(*this, callback, uid, messageNumber, peek, &fdRet, &structret)); }
void mail::addressbook::del(std::string uid, mail::callback &callback) { vector<Index>::iterator b=index.begin(), e=index.end(); while (b != e) { if (b->uid == uid) { vector<size_t> msgList; msgList.push_back(b - index.begin()); server->removeMessages(msgList, callback); return; } b++; } callback.success("OK"); }
void mail::mbox::folder::create(bool isDirectory, mail::callback &callback) const { if (isDirectory) { if (mkdir(path.c_str(), 0700) < 0) { callback.fail(path + ": " + strerror(errno)); return; } } else { int fd= ::open(path.c_str(), O_RDWR|O_CREAT|O_EXCL, 0600); if (fd < 0) { callback.fail(path + ": " + strerror(errno)); return; } close(fd); } callback.success("OK"); }
void mail::maildir::updateKeywords(const vector<size_t> &messages, const set<string> &keywords, bool setOrChange, bool changeTo, mail::callback &cb) { bool keepGoing; if (folderPath.size() == 0) { cb.success("Ok."); return; } string dir; { char *dirs=maildir_name2dir(path.c_str(), folderPath.c_str()); if (!dirs) { cb.fail(strerror(errno)); return; } try { dir=dirs; free(dirs); } catch (...) { free(dirs); LIBMAIL_THROW(LIBMAIL_THROW_EMPTY); } } if (!setOrChange) { if (!updateKeywords(dir, messages, keywords, setOrChange, changeTo, NULL, NULL)) { cb.fail(strerror(errno)); return; } } else do { struct libmail_kwGeneric g; libmail_kwgInit(&g); char *imap_lock=NULL; if (lockFolder) { int flag; imap_lock=maildir_lock(dir.c_str(), lockFolder, &flag); if (!imap_lock) { if (!flag) { libmail_kwgDestroy(&g); cb.fail(strerror(errno)); return; } } } try { if (libmail_kwgReadMaildir(&g, dir.c_str()) < 0) { if (imap_lock) { unlink(imap_lock); free(imap_lock); imap_lock=NULL; } cb.fail(strerror(errno)); return; } keepGoing=false; if (!updateKeywords(dir, messages, keywords, setOrChange, changeTo, &g, &keepGoing)) { if (imap_lock) { unlink(imap_lock); free(imap_lock); imap_lock=NULL; } libmail_kwgDestroy(&g); if (keepGoing) continue; cb.fail(strerror(errno)); return; } if (imap_lock) { unlink(imap_lock); free(imap_lock); imap_lock=NULL; } libmail_kwgDestroy(&g); } catch (...) { if (imap_lock) { unlink(imap_lock); free(imap_lock); imap_lock=NULL; } libmail_kwgDestroy(&g); throw; } } while (keepGoing); cb.success("Message keywords updated."); }
mail::mbox::mbox(bool magicInboxArg, string folderRoot, mail::callback &callback, mail::callback::disconnect &disconnect_callback) : mail::account(disconnect_callback), calledDisconnected(false), magicInbox(magicInboxArg), inboxFolder("INBOX", *this), hierarchyFolder("", *this), currentFolderReadOnly(false), folderSavedSize(0), folderSavedTimestamp(0), multiLockLock(NULL), folderDirty(false), newMessages(false), cachedMessageRfcp(NULL), cachedMessageFp(NULL), currentFolderCallback(NULL) { sigset_t ss; // Ignore SIGUSR2 from c-client sigemptyset(&ss); sigaddset(&ss, SIGUSR2); sigprocmask(SIG_BLOCK, &ss, NULL); const char *m=getenv("MAIL"); string h=mail::homedir(); struct passwd *pw=getpwuid(getuid()); if (!pw || h.size() == 0) { callback.fail("Cannot find my home directory!"); return; } inboxMailboxPath=h + "/Inbox"; // Figure out the mail spool directory. if (m && *m) inboxSpoolPath=m; else { static const char *spools[]={"/var/spool/mail", "/var/mail", "/usr/spool/mail", "/usr/mail", 0}; size_t i; for (i=0; spools[i]; i++) if (access(spools[i], X_OK) == 0) { inboxSpoolPath=string(spools[i]) + "/" + pw->pw_name; break; } if (!spools[i]) { callback.fail("Cannot determine your system mailbox location,"); return; } } if (folderRoot.size() > 0 && folderRoot[0] != '/') folderRoot=h + "/" + folderRoot; rootPath=folderRoot; // Initialize the top level folder. hierarchyFolder.path=folderRoot; hierarchyFolder.name=folder::defaultName(folderRoot); // First time through, create the top level folder directory, if // necessary. if (magicInboxArg) mkdir(folderRoot.c_str(), 0700); struct stat stat_buf; if (stat(folderRoot.c_str(), &stat_buf) == 0 && S_ISDIR(stat_buf.st_mode)) { hierarchyFolder.hasMessages(false); hierarchyFolder.hasSubFolders(true); } else { hierarchyFolder.hasMessages(true); hierarchyFolder.hasSubFolders(false); } callback.success("Mail folder opened."); }