summaryrefslogtreecommitdiffstats
path: root/libmail/nntp.C
diff options
context:
space:
mode:
Diffstat (limited to 'libmail/nntp.C')
-rw-r--r--libmail/nntp.C1489
1 files changed, 0 insertions, 1489 deletions
diff --git a/libmail/nntp.C b/libmail/nntp.C
deleted file mode 100644
index 0ef8203..0000000
--- a/libmail/nntp.C
+++ /dev/null
@@ -1,1489 +0,0 @@
-/*
-** Copyright 2003-2008, Double Precision Inc.
-**
-** See COPYING for distribution information.
-*/
-#include "libmail_config.h"
-#include "mail.H"
-#include "misc.H"
-#include "driver.H"
-#include "nntp.H"
-#include "nntpnewsrc.H"
-#include "nntpxpat.H"
-#include "copymessage.H"
-#include "search.H"
-#include "smtpinfo.H"
-#include "objectmonitor.H"
-#include "libcouriertls.h"
-#include "expungelist.H"
-#include <unicode/courier-unicode.h>
-#include <sstream>
-#include <iostream>
-#include <iomanip>
-#include <time.h>
-#include <errno.h>
-#include <unistd.h>
-#include <algorithm>
-#include <fstream>
-#include <vector>
-#include <signal.h>
-#include <set>
-#include "nntplogin2.H"
-#include "nntpfolder.H"
-#include "nntplogout.H"
-#include "nntpfetch.H"
-#include "nntpcache.H"
-#include "nntpxover.H"
-#include "nntpchecknew.H"
-#include "rfc2045/rfc2045.h"
-
-#define TIMEOUTINACTIVITY 15
-
-using namespace std;
-
-mail::nntp::nntpMessageInfo::nntpMessageInfo()
- : msgNum(0), msgFlag(0)
-{
-}
-
-mail::nntp::nntpMessageInfo::~nntpMessageInfo()
-{
-}
-
-/////////////////////////////////////////////////////////////////////////////
-
-LIBMAIL_START
-
-static bool open_nntp(mail::account *&accountRet,
- mail::account::openInfo &oi,
- mail::callback &callback,
- mail::callback::disconnect &disconnectCallback)
-{
- mail::loginInfo nntpLoginInfo;
-
- if (!mail::loginUrlDecode(oi.url, nntpLoginInfo))
- return false;
-
- if (nntpLoginInfo.method != "nntp" &&
- nntpLoginInfo.method != "nntps")
- return false;
-
- accountRet=new mail::nntp(oi.url, oi.pwd, oi.certificates,
- oi.extraString,
- oi.loginCallbackObj,
- callback,
- disconnectCallback);
- return true;
-}
-
-static bool nntp_remote(string url, bool &flag)
-{
- mail::loginInfo nntpLoginInfo;
-
- if (!mail::loginUrlDecode(url, nntpLoginInfo))
- return false;
-
- if (nntpLoginInfo.method != "nntp" &&
- nntpLoginInfo.method != "nntps")
- return false;
-
- flag=true;
- return true;
-}
-
-driver nntp_driver= { &open_nntp, &nntp_remote };
-
-LIBMAIL_END
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// Service this account.
-//
-
-void mail::nntp::handler(vector<pollfd> &fds, int &ioTimeout)
-{
- int fd_save=getfd();
-
- // Disconnect from the server, after a period of inactivity.
-
- if (inactivityTimeout)
- {
- time_t now=time(NULL);
-
- if (now + autologoutSetting < inactivityTimeout)
- // Time reset??
- {
- inactivityTimeout = now + autologoutSetting;
- }
-
- if (now >= inactivityTimeout)
- {
- installTask(new mail::nntp::LogoutTask(NULL,
- *this,
- true));
- }
- else
- {
- now = inactivityTimeout - now;
-
- if (now * 1000 <= ioTimeout)
- {
- ioTimeout = now * 1000;
- }
- }
- }
-
- if (!tasks.empty())
- {
- int t=(*tasks.begin())->getTimeout();
-
- if (t * 1000 <= ioTimeout)
- {
- ioTimeout=t;
- }
- }
-
- MONITOR(mail::nntp);
-
- process(fds, ioTimeout);
-
- if (DESTROYED())
- ioTimeout=0;
-
- if (DESTROYED() || getfd() < 0)
- {
- size_t i;
-
- for (i=fds.size(); i; )
- {
- --i;
-
- if (fds[i].fd == fd_save)
- {
- fds.erase(fds.begin()+i, fds.begin()+i+1);
- break;
- }
- }
- }
-
- return;
-}
-
-void mail::nntp::resumed()
-{
- if (!tasks.empty())
- (*tasks.begin())->resetTimeout();
-}
-
-//
-// There's something to read. NNTP tasks read one line at a time.
-
-int mail::nntp::socketRead(const std::string &readbuffer)
-{
- size_t n;
-
- if (!tasks.empty() && (n=readbuffer.find('\n')) != std::string::npos)
- {
- size_t i=n;
-
- if (i > 0 && readbuffer[i-1] == '\r')
- --i;
-
- string line=readbuffer.substr(0, i);
-
- Task *t= *tasks.begin();
-
- t->resetTimeout(); // Command is alive
- t->serverResponse(line.c_str());
- return n+1;
- }
-
- return 0;
-}
-
-//
-// Let the first task handle disconnection events.
-//
-
-void mail::nntp::disconnect(const char *reason)
-{
- string errmsg=reason ? reason:"";
-
- if (getfd() >= 0)
- {
- string errmsg2=socketDisconnect();
-
- if (errmsg2.size() > 0)
- errmsg=errmsg2;
- }
-
- if (!tasks.empty())
- (*tasks.begin())->disconnected(errmsg.c_str());
-}
-
-mail::nntp::nntp(string url, string passwd,
- std::vector<std::string> &certificates,
- string newsrcFilenameArg,
- mail::loginCallback *loginCallbackFunc,
- callback &callback,
- callback::disconnect &disconnectCallbackArg)
- : mail::fd(disconnectCallbackArg, certificates),
- inactivityTimeout(0),
- folderCallback(NULL),
- hasNewgroups(false), didCacheNewsrc(false),
- disconnectCallback(&disconnectCallbackArg),
- genericTmpFp(NULL), genericTmpRfcp(NULL)
-{
- if (newsrcFilenameArg.size() == 0)
- {
- callback.fail("Invalid NNTP login (.newsrc unspecified)");
- return;
- }
-
- newsrcFilename=newsrcFilenameArg;
-
- if (!mail::loginUrlDecode(url, savedLoginInfo))
- {
- callback.fail("Invalid NNTP URL.");
- return;
- }
- timeoutSetting=getTimeoutSetting(savedLoginInfo, "timeout", 60,
- 30, 600);
- autologoutSetting=getTimeoutSetting(savedLoginInfo, "autologout", 300,
- 5, 1800);
-
- savedLoginInfo.loginCallbackFunc=loginCallbackFunc;
- savedLoginInfo.use_ssl=savedLoginInfo.method == "nntps";
- if (passwd.size() > 0)
- savedLoginInfo.pwd=passwd;
-
- try {
- installTask(new LoginTask(&callback, *this));
- } catch (...) {
- callback.fail(strerror(errno));
- }
-}
-
-void mail::nntp::cleartmp()
-{
- if (genericTmpFp != NULL)
- {
- fclose(genericTmpFp);
- genericTmpFp=NULL;
- }
-
- if (genericTmpRfcp != NULL)
- {
- rfc2045_free(genericTmpRfcp);
- genericTmpRfcp=NULL;
- }
-}
-
-mail::nntp::~nntp()
-{
- cleartmp();
- while (!tasks.empty())
- (*tasks.begin())->disconnected("NNTP connection aborted.");
-
- if (disconnectCallback)
- {
- callback::disconnect *d=disconnectCallback;
-
- disconnectCallback=NULL;
-
- d->disconnected("Connection aborted.");
- }
- index.clear();
-}
-
-// Cache newsrc into a map
-
-void mail::nntp::cacheNewsrc()
-{
- if (didCacheNewsrc)
- return;
-
- cachedNewsrc.clear();
- ifstream i(newsrcFilename.c_str());
-
- string line;
-
- while (i.is_open() && !getline(i, line).fail())
- {
- newsrc parseLine(line);
-
- if (parseLine.newsgroupname.size() == 0)
- continue;
-
- cachedNewsrc.insert(make_pair(parseLine.newsgroupname,
- parseLine));
- }
- didCacheNewsrc=true;
-}
-
-// Save an updated newsrc line
-
-bool mail::nntp::updateOpenedNewsrc(newsrc &n)
-{
- updateCachedNewsrc();
- discardCachedNewsrc();
-
- bool updated=false;
-
- string newNewsrcFilename=newsrcFilename + ".tmp";
-
- ofstream o(newNewsrcFilename.c_str());
-
- if (o.is_open())
- {
- ifstream i(newsrcFilename.c_str());
-
- string line;
-
- while (i.is_open() && !getline(i, line).fail())
- {
- newsrc parseLine(line);
-
- if (parseLine.newsgroupname == n.newsgroupname)
- {
- o << (string)n << endl;
- updated=true;
- }
- else
- o << line << endl;
- }
-
- if (!updated)
- o << (string)n << endl;
-
- o << flush;
- o.close();
-
- if (!o.fail() && !o.bad() &&
- rename(newNewsrcFilename.c_str(),
- newsrcFilename.c_str()) == 0)
- return true;
- }
- return false;
-}
-
-// For speed, we sort the cachedNewsrc by ptrs
-
-class mail::nntp::cachedNewsrcSort {
-public:
- bool operator()(newsrc *a, newsrc *b)
- {
- return a->newsgroupname < b->newsgroupname;
- }
-};
-
-// Save updated newsrc cache
-
-bool mail::nntp::updateCachedNewsrc()
-{
- if (!didCacheNewsrc)
- return true;
-
- vector<newsrc *> vec;
-
- vec.reserve(cachedNewsrc.size());
-
- map<string, newsrc>::iterator b=cachedNewsrc.begin(),
- e=cachedNewsrc.end();
-
- while (b != e)
- {
- vec.push_back(&b->second);
- b++;
- }
-
- sort(vec.begin(), vec.end(), cachedNewsrcSort());
-
- string newNewsrcFilename=newsrcFilename + ".tmp";
-
- ofstream o(newNewsrcFilename.c_str());
-
- if (o.is_open())
- {
- // Copy any extra lines...
-
- ifstream i(newsrcFilename.c_str());
-
- string line;
-
- while (i.is_open() && !getline(i, line).fail())
- {
- if (line[0] == '#')
- {
- o << line << endl;
- continue;
- }
- }
- i.close();
-
- vector<newsrc *>::iterator b=vec.begin(), e=vec.end();
-
- while (b != e)
- {
- o << (string)**b << endl;
- b++;
- }
- o << flush;
- o.close();
-
- if (!o.fail() && !o.bad() &&
- rename(newNewsrcFilename.c_str(),
- newsrcFilename.c_str()) == 0)
- return true;
- }
- return false;
-}
-
-// Discard cached newsrc
-
-void mail::nntp::discardCachedNewsrc()
-{
- cachedNewsrc.clear();
- didCacheNewsrc=false;
-}
-
-// Create a newsrc line based on the currently open folder index
-
-void mail::nntp::createNewsrc(newsrc &n)
-{
- n.msglist.clear();
-
- vector<nntpMessageInfo>::iterator
- b=index.begin(), e=index.end();
-
- if (b != e)
- {
- bool first=true;
-
- msgnum_t lastNum=0;
-
- while (b != e)
- {
- if (first)
- {
- if (b->msgNum > 1)
- n.msglist.push_back(make_pair(1,
- b->msgNum-1)
- );
- }
- else if (lastNum+1 != b->msgNum)
- n.msglist.push_back(make_pair(lastNum+1,
- b->msgNum-1));
- first=false;
- lastNum= b->msgNum;
- b++;
- }
- }
- else if (hiWatermark > 1)
- {
- n.msglist.push_back(make_pair(1, hiWatermark-1));
- }
-}
-
-void mail::nntp::installTask(Task *taskp)
-{
- if (taskp == NULL)
- LIBMAIL_THROW((strerror(errno)));
-
- bool wasEmpty=tasks.empty();
-
- tasks.insert(tasks.end(), taskp);
- inactivityTimeout=0; // We're active now
-
- if (wasEmpty)
- {
- Task *p= *tasks.begin();
-
- p->resetTimeout();
- p->installedTask();
- }
-}
-
-void mail::nntp::logout(callback &callback)
-{
- installTask(new mail::nntp::LogoutTask(&callback, *this, false));
-}
-
-void mail::nntp::checkNewMail(callback &callback)
-{
- if (openedGroup.size() > 0)
- installTask(new mail::nntp::CheckNewTask(&callback, *this,
- openedGroup));
- else
- callback.success("Ok");
-}
-
-bool mail::nntp::hasCapability(string capability)
-{
- if (capability == LIBMAIL_CHEAPSTATUS)
- return true;
-
- return false;
-}
-
-string mail::nntp::getCapability(string capability)
-{
- if (capability == LIBMAIL_SERVERTYPE)
- return "nntp";
-
- if (capability == LIBMAIL_SERVERDESCR)
- return "Usenet server";
-
- return "";
-}
-
-mail::folder *mail::nntp::folderFromString(string s)
-{
- string words[3];
-
- words[0]="";
- words[1]="";
- words[2]="";
-
- int i=0;
-
- string::iterator b=s.begin(), e=s.end();
-
- while (b != e)
- {
- if (*b == ':')
- {
- b++;
- ++i;
- continue;
- }
-
- if (*b == '\\')
- {
- b++;
- if (b == e)
- break;
- }
-
- if (i < 3)
- words[i].append(&*b, 1);
- b++;
- }
-
- return new mail::nntp::folder(this, words[2],
- strchr(words[0].c_str(), 'F') != NULL,
- strchr(words[0].c_str(), 'D') != NULL);
-}
-
-void mail::nntp::readTopLevelFolders(callback::folderList &callback1,
- callback &callback2)
-{
- mail::nntp::folder subscribed(this, FOLDER_SUBSCRIBED,
- false, true);
- mail::nntp::folder all(this, FOLDER_NEWSRC,
- false, true);
- mail::nntp::folder newnews(this, FOLDER_CHECKNEW,
- false, true);
- mail::nntp::folder refresh(this, FOLDER_REFRESH,
- false, true);
-
- vector<const mail::folder *> v;
-
- v.push_back(&subscribed);
- v.push_back(&all);
- v.push_back(&newnews);
- v.push_back(&refresh);
-
- callback1.success(v);
- callback2.success("OK");
-}
-
-void mail::nntp::findFolder(string folder,
- callback::folderList &callback1,
- callback &callback2)
-{
- if (folder.size() == 0 ||
- (folder[0] == '/' && folder.find('.') == std::string::npos))
- {
- mail::nntp::folder dummy(this, folder, false, true);
-
- vector<const mail::folder *> vec;
-
- vec.push_back(&dummy);
-
- callback1.success(vec);
- callback2.success("OK");
- return;
- }
-
- if (folder.size() > sizeof(FOLDER_SUBSCRIBED) &&
- folder.substr(0, sizeof(FOLDER_SUBSCRIBED)) ==
- FOLDER_SUBSCRIBED ".")
- {
- mail::nntp::folder dummy(this, folder, true, false);
-
- vector<const mail::folder *> vec;
-
- vec.push_back(&dummy);
-
- callback1.success(vec);
- callback2.success("OK");
- return;
- }
-
- bool foundFolder=false;
- bool foundSubFolders=false;
-
- {
- ifstream i(newsrcFilename.c_str());
-
- if (i.is_open())
- {
- string line;
-
- while (i.is_open() && !getline(i, line).fail())
- {
- newsrc parseLine(line);
-
- if (parseLine.newsgroupname.size() == 0)
- continue;
-
- string s=FOLDER_NEWSRC "." + parseLine.newsgroupname;
-
- if (s == folder)
- foundFolder=true;
-
- if (s.size() > folder.size() &&
- s.substr(0, folder.size()) == folder &&
- s[folder.size()] == '.')
- foundSubFolders = true;
- }
- }
- }
-
- if (!foundFolder)
- foundSubFolders=true;
-
- mail::nntp::folder dummy(this, folder, foundFolder,
- foundSubFolders);
-
- vector<const mail::folder *> vec;
-
- vec.push_back(&dummy);
-
- callback1.success(vec);
- callback2.success("OK");
-}
-
-string mail::nntp::translatePath(string path)
-{
- // Evil trick: "" gets as the fake top-level hierarchy,
- // readTopLevelFolders. Otherwise, unless the path already starts with
- // a ".", prepend the SUBSCRIBED trunc.
-
- if (path.size() > 0 && path[0] != '/')
- return FOLDER_SUBSCRIBED "." + path;
-
- return path;
-}
-
-mail::folder *mail::nntp::getSendFolder(const smtpInfo &info,
- const mail::folder *folder,
- std::string &errmsg)
-{
- if (info.recipients.size() == 0 &&
- folder == NULL &&
- info.options.find("POST") != info.options.end())
- {
- // Sanity check
-
-
- mail::folder *f=new mail::nntp::folder(this, "", false,
- true);
- // Any of our folders will do the trick.
-
- if (!f)
- errmsg=strerror(errno);
- return f;
- }
-
- return mail::account::getSendFolder(info, folder, errmsg);
-}
-
-void mail::nntp::readMessageAttributes(const vector<size_t> &messages,
- MessageAttributes attributes,
- callback::message &callback)
-{
- bool useXover;
-
- if (attributes & MESSAGESIZE)
- useXover=true;
- else if (attributes & MIMESTRUCTURE)
- useXover=false;
- else if (attributes & (ENVELOPE | ARRIVALDATE))
- useXover=true;
- else
- useXover=false;
-
- if (useXover)
- {
- installTask(new XoverTask(&callback, *this,
- openedGroup, messages, attributes));
- return;
- }
-
- genericAttributes(this, this, messages, attributes, callback);
-}
-
-bool mail::nntp::fixGenericMessageNumber(std::string uid, size_t &msgNum)
-{
- msgnum_t n;
-
- istringstream i(uid);
-
- i >> n;
-
- if (i.bad() || i.fail())
- {
- return false;
- }
-
- // Need to fix up the message #
-
- size_t cnt=getFolderIndexSize();
-
- if (cnt <= msgNum)
- {
- msgNum=cnt;
- if (msgNum == 0)
- {
- return false;
- }
- --msgNum;
- }
-
- while (n > index[msgNum].msgNum)
- if (++msgNum >= cnt)
- {
- return false;
- }
-
- while (msgNum > 0 && n < index[msgNum].msgNum)
- --msgNum;
-
- if (n != index[msgNum].msgNum)
- {
- return false;
- }
-
- return true;
-}
-
-void mail::nntp::readMessageContent(const vector<size_t> &messages,
- bool peek,
- enum mail::readMode readType,
- callback::message &callback)
-{
- genericReadMessageContent(this, this, messages, peek,
- readType, callback);
-}
-
-void mail::nntp::readMessageContent(size_t messageNum,
- bool peek,
- const mimestruct &msginfo,
- enum mail::readMode readType,
- callback::message &callback)
-{
- genericReadMessageContent(this, this, messageNum, peek, msginfo,
- readType, callback);
-}
-
-void mail::nntp::readMessageContentDecoded(size_t messageNum,
- bool peek,
- const mimestruct &msginfo,
- callback::message &callback)
-{
- genericReadMessageContentDecoded(this, this, messageNum, peek,
- msginfo, callback);
-}
-
-size_t mail::nntp::getFolderIndexSize()
-{
- return openedGroup.size() == 0 ? 0:index.size();
-}
-
-mail::messageInfo mail::nntp::getFolderIndexInfo(size_t msgNum)
-{
- if (msgNum < getFolderIndexSize())
- {
- messageInfo dummy;
-
- unsigned char n=index[msgNum].msgFlag;
-
- dummy.marked= !!(n & IDX_FLAGGED);
- dummy.deleted=!!(n & IDX_DELETED);
-
- ostringstream o;
-
- o << index[msgNum].msgNum;
-
- dummy.uid=o.str();
- return dummy;
- }
-
- return messageInfo();
-}
-
-void mail::nntp::saveFolderIndexInfo(size_t msgNum,
- const messageInfo &msgInfo,
- callback &callback)
-{
- if (msgNum < getFolderIndexSize())
- {
- unsigned char n=0;
-
- if (msgInfo.marked)
- n |= IDX_FLAGGED;
-
- if (msgInfo.deleted)
- n |= IDX_DELETED;
-
- index[msgNum].msgFlag=n;
- if (openedGroup.size() > 0)
- folderCallback->messageChanged(msgNum);
- }
- callback.success("Message status updated.");
-}
-
-void mail::nntp::genericMarkRead(size_t messageNumber)
-{
-}
-
-void mail::nntp::updateFolderIndexFlags(const vector<size_t> &messages,
- bool doFlip,
- bool enableDisable,
- const messageInfo &flags,
- callback &callback)
-{
- vector<size_t>::const_iterator b, e;
-
- b=messages.begin();
- e=messages.end();
-
- size_t n=getFolderIndexSize();
-
- while (b != e)
- {
- size_t i= *b++;
-
- if (i < n)
- {
- messageInfo dummy;
-
- unsigned char n=index[i].msgFlag;
-
- dummy.marked= !!(n & IDX_FLAGGED);
- dummy.deleted=!!(n & IDX_DELETED);
-
-#define DOFLAG(d, field, dummy2) \
- if (flags.field) \
- { \
- dummy.field=\
- doFlip ? !dummy.field\
- : enableDisable; \
- }
-
- LIBMAIL_MSGFLAGS;
-#undef DOFLAG
- n=0;
-
- if (dummy.marked)
- n |= IDX_FLAGGED;
-
- if (dummy.deleted)
- n |= IDX_DELETED;
- index[i].msgFlag=n;
- }
- }
-
- b=messages.begin();
- e=messages.end();
-
- MONITOR(mail::nntp);
-
- while (!DESTROYED() && b != e)
- {
- size_t i= *b++;
-
- if (i < n && folderCallback)
- folderCallback->messageChanged(i);
- }
-
- saveSnapshot();
- callback.success("OK");
-}
-
-void mail::nntp::getFolderKeywordInfo(size_t msgNum,
- set<string> &keywords)
-{
- keywords.clear();
- if (msgNum >= index.size())
- return;
- index[msgNum].keywords.getFlags(keywords);
-}
-
-bool mail::nntp::genericProcessKeyword(size_t msgNum,
- updateKeywordHelper &helper)
-{
- if (msgNum >= index.size())
- return true;
- helper.doUpdateKeyword(index[msgNum].keywords, keywordHashtable);
- return true;
-}
-
-
-void mail::nntp::updateKeywords(const std::vector<size_t> &messages,
- const std::set<std::string> &keywords,
- bool setOrChange,
- // false: set, true: see changeTo
- bool changeTo,
- callback &cb)
-{
- MONITOR(mail::nntp);
-
- genericUpdateKeywords(messages, keywords, setOrChange, changeTo,
- folderCallback, this, cb);
-
- if (!DESTROYED())
- saveSnapshot();
-}
-
-
-void mail::nntp::updateFolderIndexInfo(callback &callback)
-{
- vector<size_t> deletedMsgs;
-
- size_t n=getFolderIndexSize();
- size_t i;
-
- for (i=0; i<n; i++)
- if (index[i].msgFlag & IDX_DELETED)
- deletedMsgs.push_back(i);
-
- removeMessages(deletedMsgs, callback);
-}
-
-void mail::nntp::removeMessages(const vector<size_t> &messages,
- callback &callback)
-{
- if (openedGroup.size() == 0)
- {
- callback.success("Ok.");
- return;
- }
-
- set<size_t> msgNumSet;
-
- msgNumSet.insert(messages.begin(), messages.end());
-
- list< pair<size_t, size_t> > removedList;
- size_t n=getFolderIndexSize();
-
- MONITOR(mail::nntp);
-
- while (!DESTROYED() && n)
- {
- --n;
- if (msgNumSet.find(n) == msgNumSet.end())
- continue;
-
- index.erase(index.begin() + n);
-
- if (!removedList.empty() &&
- removedList.begin()->first == n+1)
- {
- removedList.begin()->first--;
- continue;
- }
-
- if (removedList.size() >= 100)
- {
- vector< pair<size_t, size_t> > vec;
-
- vec.insert(vec.end(), removedList.begin(),
- removedList.end());
- removedList.clear();
-
- if (folderCallback)
- folderCallback->messagesRemoved(vec);
- }
-
- removedList.push_front(make_pair(n, n));
- }
-
- if (!DESTROYED() && removedList.size() > 0)
- {
- vector< pair<size_t, size_t> > vec;
-
- vec.insert(vec.end(), removedList.begin(),
- removedList.end());
- removedList.clear();
-
- if (folderCallback)
- folderCallback->messagesRemoved(vec);
- }
-
- if (!DESTROYED())
- {
- updateCachedNewsrc();
- discardCachedNewsrc();
-
- newsrc newNewsrc;
-
- createNewsrc(newNewsrc);
- newNewsrc.newsgroupname=openedGroup;
- newNewsrc.subscribed=true;
- updateOpenedNewsrc(newNewsrc);
-
- saveSnapshot();
- }
-
- callback.success("Group updated.");
-}
-
-void mail::nntp::saveSnapshot()
-{
- if (folderCallback)
- {
- ostringstream o;
-
- o << loWatermark << '-' << hiWatermark;
-
- folderCallback->saveSnapshot(o.str());
- }
-}
-
-void mail::nntp::copyMessagesTo(const vector<size_t> &messages,
- mail::folder *copyTo,
- callback &callback)
-{
- copyMessages::copy(this, messages, copyTo, callback);
-}
-
-void mail::nntp::searchMessages(const searchParams &searchInfo,
- searchCallback &callback)
-{
- string hdr;
- switch (searchInfo.criteria) {
- case searchParams::from:
- hdr="FROM";
- break;
- case searchParams::to:
- hdr="TO";
- break;
- case searchParams::cc:
- hdr="CC";
- break;
- case searchParams::bcc:
- hdr="BCC";
- break;
- case searchParams::subject:
- hdr="SUBJECT";
- break;
- case searchParams::header:
- hdr=searchInfo.param1;
- break;
- default:
- break;
- }
-
- if (hdr.size() > 0)
- {
- unicode_char *uc;
- size_t ucsize;
- unicode_convert_handle_t
- h(unicode_convert_tou_init(searchInfo.charset.c_str(),
- &uc, &ucsize, 0));
-
- if (h)
- {
- unicode_convert(h, searchInfo.param2.c_str(),
- searchInfo.param2.size());
-
- if (unicode_convert_deinit(h, NULL))
- uc=NULL;
- }
- else
- {
- uc=NULL;
- }
-
- if (uc)
- {
- size_t i;
-
- for (i=0; i<ucsize; i++)
- if (uc[i] < 32 || uc[i] >= 127)
- break;
-
- if (i < ucsize)
- {
- free(uc);
- }
- else
- {
- char *p;
- size_t psize;
-
- h=unicode_convert_fromu_init("utf-8",
- &p, &psize, 1);
-
- if (h)
- {
- unicode_convert_uc(h, uc, ucsize);
- if (unicode_convert_deinit(h, NULL))
- p=NULL;
- }
- else
- p=NULL;
-
- free(uc);
-
- if (!p)
- {
- callback.fail(strerror(errno));
- return;
- }
-
- try {
- string s=p;
- searchMessagesXpat(hdr, s,
- searchInfo
- .searchNot,
- searchInfo.scope,
- searchInfo.rangeLo,
- searchInfo.rangeHi,
- callback);
- free(p);
- } catch (...) {
- free(p);
- callback.fail(strerror(errno));
- }
- return;
- }
- }
- }
-
- switch (searchInfo.criteria) {
- case searchParams::replied:
- case searchParams::deleted:
- case searchParams::draft:
- case searchParams::unread:
- break;
- default:
- callback.fail("Not implemented.");
- return;
- }
-
- searchMessages::search(callback, searchInfo, this);
-}
-
-void mail::nntp::searchMessagesXpat(string hdr, string srch,
- bool searchNot,
- searchParams::Scope searchScope,
- size_t rangeLo,
- size_t rangeHi,
- searchCallback &callback)
-{
-
- string::iterator b, e;
-
- b=hdr.begin();
- e=hdr.end();
-
- while (b != e)
- {
- if (*b < ' ' || *b >= 127)
- {
- errno=EINVAL;
- callback.fail(strerror(errno));
- }
- ++b;
- }
-
- b=srch.begin();
- e=srch.end();
-
- while (b != e)
- {
- if (*b < ' ' || *b >= 127)
- {
- errno=EINVAL;
- callback.fail(strerror(errno));
- }
- ++b;
- }
-
- XpatTaskCallback *cb=new XpatTaskCallback(&callback);
-
- if (!cb)
- {
- callback.fail(strerror(errno));
- return;
- }
-
- try {
- installTask(new XpatTask(cb, *this,
- openedGroup,
- hdr, srch, searchNot,
- searchScope, rangeLo, rangeHi));
- } catch (...) {
- delete cb;
- throw;
- }
-}
-
-void mail::nntp::genericMessageRead(string uid,
- size_t messageNumber,
- bool peek,
- mail::readMode getType,
- callback::message &callback)
-{
- if (openedGroup.size() == 0)
- {
- callback.fail("Invalid message number.");
- return;
- }
-
- if (fixGenericMessageNumber(uid, messageNumber) &&
- genericCachedUid(uid))
- {
- // We can optimize by taking this path
-
- vector<size_t> vec;
-
- vec.push_back(messageNumber);
- readMessageContent(vec, peek, getType, callback);
- return;
- }
-
- installTask(new FetchTask(&callback, *this, openedGroup,
- messageNumber, uid, getType));
-}
-
-void mail::nntp::genericMessageSize(string uid,
- size_t messageNumber,
- callback::message &callback)
-{
- if (!fixGenericMessageNumber(uid, messageNumber))
- {
- callback.fail("Invalid message number.");
- return;
- }
-
- callback.messageSizeCallback(messageNumber, 0);
-
- callback.success("OK"); // TODO
-}
-
-void mail::nntp::genericGetMessageFd(string uid,
- size_t messageNumber,
- bool peek,
- int &fdRet,
- callback &callback)
-{
- if (openedGroup.size() == 0)
- {
- callback.fail("Invalid message number.");
- return;
- }
-
- if (genericTmpFp && uid == cachedUid)
- {
- fdRet=fileno(genericTmpFp);
- callback.success("OK");
- return;
- }
-
- installTask(new CacheTask(&callback, *this, openedGroup,
- messageNumber, uid,
- &fdRet, NULL));
-}
-
-bool mail::nntp::genericCachedUid(string uid)
-{
- return genericTmpFp && uid == cachedUid;
-}
-
-void mail::nntp::genericGetMessageStruct(string uid,
- size_t messageNumber,
- struct rfc2045 *&structRet,
- callback &callback)
-{
- if (openedGroup.size() == 0)
- {
- callback.fail("Invalid message number.");
- return;
- }
-
- if (genericTmpRfcp && uid == cachedUid)
- {
- structRet=genericTmpRfcp;
- callback.success("OK");
- return;
- }
-
- installTask(new CacheTask(&callback, *this, openedGroup,
- messageNumber, uid,
- NULL, &structRet));
-}
-
-/////////////////////////////////////////////////////////////////////////////
-//
-// The basic NNTP task
-
-mail::nntp::Task::Task(callback *callbackArg,
- nntp &myserverArg)
- : callbackPtr(callbackArg), myserver( &myserverArg),
- defaultTimeout( time(NULL) + myserver->timeoutSetting)
-{
-}
-
-mail::nntp::Task::~Task()
-{
- done(); // Make sure that any callback gets invoked
-}
-
-void mail::nntp::Task::resetTimeout()
-{
- defaultTimeout=time(NULL) + myserver->timeoutSetting;
-}
-
-void mail::nntp::Task::done()
-{
- callback *cb=callbackPtr;
-
- callbackPtr=NULL;
-
- if (myserver != NULL) // Kilroy was here
- {
- if ((*myserver->tasks.begin()) != this)
- {
- cerr << "INTERNAL ERROR: mail::nntp::Task::done()"
- << endl;
- abort();
- }
-
- myserver->tasks.erase(myserver->tasks.begin());
-
- try {
- if (!myserver->tasks.empty())
- {
- Task *p= *myserver->tasks.begin();
-
- p->resetTimeout();
- p->installedTask();
- }
- else
- emptyQueue();
-
- } catch (...) {
- myserver=NULL;
- delete this;
- if (cb)
- cb->fail("Operation aborted.");
- throw;
- }
-
-
- myserver=NULL;
- delete this;
- }
-
- if (cb)
- cb->fail("Operation aborted.");
-}
-
-void mail::nntp::Task::emptyQueue()
-{
- myserver->inactivityTimeout=time(NULL) + myserver->autologoutSetting;
-}
-
-// Subclass succeeded
-
-void mail::nntp::Task::success(string message)
-{
- callback *cb=callbackPtr;
-
- callbackPtr=NULL;
- done();
- if (cb)
- cb->success(message);
-}
-
-// Subclass failed
-
-void mail::nntp::Task::fail(string message)
-{
- callback *cb=callbackPtr;
-
- callbackPtr=NULL;
- done();
- if (cb)
- cb->fail(message);
-}
-
-// Check for task timeout.
-
-int mail::nntp::Task::getTimeout()
-{
- time_t now;
-
- time(&now);
-
- if (now < defaultTimeout)
- return defaultTimeout - now;
-
- string errmsg=myserver->socketDisconnect();
-
- if (errmsg.size() == 0)
- errmsg="Server timed out.";
-
- disconnected(errmsg.c_str());
- return 0;
-}
-
-// Server has disconnected.
-// The default implementation takes this task off the queue,
-// calls the next Task's disconnect method, then deletes
-// itself.
-
-void mail::nntp::Task::disconnected(const char *reason)
-{
- callback *cb=callbackPtr;
-
- callbackPtr=NULL;
-
- if ((*myserver->tasks.begin()) != this)
- {
- cerr << "INTERNAL ERROR: mail::nntp::Task::done()" << endl;
- abort();
- }
-
- nntp *s=myserver;
-
- myserver=NULL;
-
- s->tasks.erase(s->tasks.begin());
- delete this;
-
- if (!s->tasks.empty())
- (*s->tasks.begin())->disconnected(reason);
-
- if (cb)
- cb->fail(reason);
-}
-
-void mail::nntp::Task::installedTask()
-{
-}