|
|
|
/*
|
|
|
|
knnntpclient.cpp
|
|
|
|
|
|
|
|
KNode, the KDE newsreader
|
|
|
|
Copyright (c) 1999-2001 the KNode authors.
|
|
|
|
See file AUTHORS for details
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software Foundation,
|
|
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, US
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <tdelocale.h>
|
|
|
|
#include <tqtextcodec.h>
|
|
|
|
#include <tqmutex.h>
|
|
|
|
|
|
|
|
#include "kngroupmanager.h"
|
|
|
|
#include "knnntpclient.h"
|
|
|
|
#include "utilities.h"
|
|
|
|
|
|
|
|
|
|
|
|
KNNntpClient::KNNntpClient(int NfdPipeIn, int NfdPipeOut, TQMutex& nntpMutex)
|
|
|
|
: KNProtocolClient(NfdPipeIn,NfdPipeOut), mutex(nntpMutex)
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
KNNntpClient::~KNNntpClient()
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
|
|
// examines the job and calls the suitable handling method
|
|
|
|
void KNNntpClient::processJob()
|
|
|
|
{
|
|
|
|
switch (job->type()) {
|
|
|
|
case KNJobData::JTLoadGroups :
|
|
|
|
doLoadGroups();
|
|
|
|
break;
|
|
|
|
case KNJobData::JTFetchGroups :
|
|
|
|
doFetchGroups();
|
|
|
|
break;
|
|
|
|
case KNJobData::JTCheckNewGroups :
|
|
|
|
doCheckNewGroups();
|
|
|
|
break;
|
|
|
|
case KNJobData::JTfetchNewHeaders :
|
|
|
|
case KNJobData::JTsilentFetchNewHeaders :
|
|
|
|
doFetchNewHeaders();
|
|
|
|
break;
|
|
|
|
case KNJobData::JTfetchArticle :
|
|
|
|
doFetchArticle();
|
|
|
|
break;
|
|
|
|
case KNJobData::JTpostArticle :
|
|
|
|
doPostArticle();
|
|
|
|
break;
|
|
|
|
case KNJobData::JTfetchSource :
|
|
|
|
doFetchSource();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: KNNntpClient::processJob(): mismatched job");
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::doLoadGroups()
|
|
|
|
{
|
|
|
|
KNGroupListData *target = static_cast<KNGroupListData *>(job->data());
|
|
|
|
sendSignal(TSloadGrouplist);
|
|
|
|
|
|
|
|
if (!target->readIn(this))
|
|
|
|
job->setErrorString(i18n("Unable to read the group list file"));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::doFetchGroups()
|
|
|
|
{
|
|
|
|
KNGroupListData *target = static_cast<KNGroupListData *>(job->data());
|
|
|
|
|
|
|
|
sendSignal(TSdownloadGrouplist);
|
|
|
|
errorPrefix = i18n("The group list could not be retrieved.\nThe following error occurred:\n");
|
|
|
|
|
|
|
|
progressValue = 100;
|
|
|
|
predictedLines = 30000; // rule of thumb ;-)
|
|
|
|
|
|
|
|
if (!sendCommandWCheck("LIST",215)) // 215 list of newsgroups follows
|
|
|
|
return;
|
|
|
|
|
|
|
|
char *s, *line;
|
|
|
|
TQString name;
|
|
|
|
KNGroup::Status status;
|
|
|
|
bool subscribed;
|
|
|
|
|
|
|
|
while (getNextLine()) {
|
|
|
|
line = getCurrentLine();
|
|
|
|
if (line[0]=='.') {
|
|
|
|
if (line[1]=='.')
|
|
|
|
line++; // collapse double period into one
|
|
|
|
else
|
|
|
|
if (line[1]==0)
|
|
|
|
break; // message complete
|
|
|
|
}
|
|
|
|
s = strchr(line,' ');
|
|
|
|
if(!s) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: retrieved broken group-line - ignoring");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
s[0] = 0; // cut string
|
|
|
|
|
|
|
|
name = TQString::fromUtf8(line);
|
|
|
|
|
|
|
|
if (target->subscribed.contains(name)) {
|
|
|
|
target->subscribed.remove(name); // group names are unique, we wont find it again anyway...
|
|
|
|
subscribed = true;
|
|
|
|
} else
|
|
|
|
subscribed = false;
|
|
|
|
|
|
|
|
while (s[1]!=0) s++; // the last character determines the moderation status
|
|
|
|
switch (s[0]) {
|
|
|
|
case 'n' : status = KNGroup::readOnly;
|
|
|
|
break;
|
|
|
|
case 'y' : status = KNGroup::postingAllowed;
|
|
|
|
break;
|
|
|
|
case 'm' : status = KNGroup::moderated;
|
|
|
|
break;
|
|
|
|
default : status = KNGroup::unknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
target->groups->append(new KNGroupInfo(name,TQString(),false,subscribed,status));
|
|
|
|
}
|
|
|
|
doneLines++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!job->success() || job->canceled())
|
|
|
|
return; // stopped...
|
|
|
|
|
|
|
|
TQPtrVector<KNGroupInfo> tempVector;
|
|
|
|
target->groups->toVector(&tempVector);
|
|
|
|
tempVector.sort();
|
|
|
|
|
|
|
|
if (target->getDescriptions) {
|
|
|
|
errorPrefix = i18n("The group descriptions could not be retrieved.\nThe following error occurred:\n");
|
|
|
|
progressValue = 100;
|
|
|
|
doneLines = 0;
|
|
|
|
predictedLines = target->groups->count();
|
|
|
|
|
|
|
|
sendSignal(TSdownloadDesc);
|
|
|
|
sendSignal(TSprogressUpdate);
|
|
|
|
|
|
|
|
int rep;
|
|
|
|
if (!sendCommand("LIST NEWSGROUPS",rep))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rep == 215) { // 215 informations follows
|
|
|
|
TQString description;
|
|
|
|
KNGroupInfo info;
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
while (getNextLine()) {
|
|
|
|
line = getCurrentLine();
|
|
|
|
if (line[0]=='.') {
|
|
|
|
if (line[1]=='.')
|
|
|
|
line++; // collapse double period into one
|
|
|
|
else
|
|
|
|
if (line[1]==0)
|
|
|
|
break; // message complete
|
|
|
|
}
|
|
|
|
s = line;
|
|
|
|
while (*s != '\0' && *s != '\t' && *s != ' ') s++;
|
|
|
|
if (*s == '\0') {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: retrieved broken group-description - ignoring");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
s[0] = 0; // terminate groupname
|
|
|
|
s++;
|
|
|
|
while (*s == ' ' || *s == '\t') s++; // go on to the description
|
|
|
|
|
|
|
|
name = TQString::fromUtf8(line);
|
|
|
|
if (target->codecForDescriptions) // some countries use local 8 bit characters in the tag line
|
|
|
|
description = target->codecForDescriptions->toUnicode(s);
|
|
|
|
else
|
|
|
|
description = TQString::fromLocal8Bit(s);
|
|
|
|
info.name = name;
|
|
|
|
|
|
|
|
if ((pos=tempVector.bsearch(&info))!=-1)
|
|
|
|
tempVector[pos]->description = description;
|
|
|
|
}
|
|
|
|
doneLines++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!job->success() || job->canceled())
|
|
|
|
return; // stopped...
|
|
|
|
}
|
|
|
|
|
|
|
|
target->groups->setAutoDelete(false);
|
|
|
|
tempVector.toList(target->groups);
|
|
|
|
target->groups->setAutoDelete(true);
|
|
|
|
|
|
|
|
sendSignal(TSwriteGrouplist);
|
|
|
|
if (!target->writeOut())
|
|
|
|
job->setErrorString(i18n("Unable to write the group list file"));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::doCheckNewGroups()
|
|
|
|
{
|
|
|
|
KNGroupListData *target = static_cast<KNGroupListData *>(job->data());
|
|
|
|
|
|
|
|
sendSignal(TSdownloadNewGroups);
|
|
|
|
errorPrefix = i18n("New groups could not be retrieved.\nThe following error occurred:\n");
|
|
|
|
|
|
|
|
progressValue = 100;
|
|
|
|
predictedLines = 30; // rule of thumb ;-)
|
|
|
|
|
|
|
|
TQCString cmd;
|
|
|
|
cmd.sprintf("NEWGROUPS %.2d%.2d%.2d 000000",target->fetchSince.year()%100,target->fetchSince.month(),target->fetchSince.day());
|
|
|
|
if (!sendCommandWCheck(cmd,231)) // 231 list of new newsgroups follows
|
|
|
|
return;
|
|
|
|
|
|
|
|
char *s, *line;
|
|
|
|
TQString name;
|
|
|
|
KNGroup::Status status;
|
|
|
|
TQPtrList<KNGroupInfo> tmpList;
|
|
|
|
tmpList.setAutoDelete(true);
|
|
|
|
|
|
|
|
while (getNextLine()) {
|
|
|
|
line = getCurrentLine();
|
|
|
|
if (line[0]=='.') {
|
|
|
|
if (line[1]=='.')
|
|
|
|
line++; // collapse double period into one
|
|
|
|
else
|
|
|
|
if (line[1]==0)
|
|
|
|
break; // message complete
|
|
|
|
}
|
|
|
|
s = strchr(line,' ');
|
|
|
|
if(!s) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: retrieved broken group-line - ignoring");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
s[0] = 0; // cut string
|
|
|
|
name = TQString::fromUtf8(line);
|
|
|
|
|
|
|
|
while (s[1]!=0) s++; // the last character determines the moderation status
|
|
|
|
switch (s[0]) {
|
|
|
|
case 'n' : status = KNGroup::readOnly;
|
|
|
|
break;
|
|
|
|
case 'y' : status = KNGroup::postingAllowed;
|
|
|
|
break;
|
|
|
|
case 'm' : status = KNGroup::moderated;
|
|
|
|
break;
|
|
|
|
default : status = KNGroup::unknown;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpList.append(new KNGroupInfo(name,TQString(),true,false,status));
|
|
|
|
}
|
|
|
|
doneLines++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!job->success() || job->canceled())
|
|
|
|
return; // stopped...
|
|
|
|
|
|
|
|
if (target->getDescriptions) {
|
|
|
|
errorPrefix = i18n("The group descriptions could not be retrieved.\nThe following error occurred:\n");
|
|
|
|
progressValue = 100;
|
|
|
|
doneLines = 0;
|
|
|
|
predictedLines = tmpList.count()*3;
|
|
|
|
|
|
|
|
sendSignal(TSdownloadDesc);
|
|
|
|
sendSignal(TSprogressUpdate);
|
|
|
|
|
|
|
|
cmd = "LIST NEWSGROUPS ";
|
|
|
|
TQStrList desList;
|
|
|
|
char *s;
|
|
|
|
int rep;
|
|
|
|
|
|
|
|
for (KNGroupInfo *group=tmpList.first(); group; group=tmpList.next()) {
|
|
|
|
if (!sendCommand(cmd+group->name.utf8(),rep))
|
|
|
|
return;
|
|
|
|
if (rep != 215) // 215 informations follows
|
|
|
|
break;
|
|
|
|
desList.clear();
|
|
|
|
if (!getMsg(desList))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (desList.count()>0) { // group has a description
|
|
|
|
s = desList.first();
|
|
|
|
while (*s !=- '\0' && *s != '\t' && *s != ' ') s++;
|
|
|
|
if (*s == '\0') {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: retrieved broken group-description - ignoring");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
while (*s == ' ' || *s == '\t') s++; // go on to the description
|
|
|
|
if (target->codecForDescriptions) // some countries use local 8 bit characters in the tag line
|
|
|
|
group->description = target->codecForDescriptions->toUnicode(s);
|
|
|
|
else
|
|
|
|
group->description = TQString::fromLocal8Bit(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
sendSignal(TSloadGrouplist);
|
|
|
|
|
|
|
|
if (!target->readIn()) {
|
|
|
|
job->setErrorString(i18n("Unable to read the group list file"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
target->merge(&tmpList);
|
|
|
|
sendSignal(TSwriteGrouplist);
|
|
|
|
if (!target->writeOut()) {
|
|
|
|
job->setErrorString(i18n("Unable to write the group list file"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::doFetchNewHeaders()
|
|
|
|
{
|
|
|
|
KNGroup* target=static_cast<KNGroup*>(job->data());
|
|
|
|
char* s;
|
|
|
|
int first=0, last=0, oldlast=0, toFetch=0, rep=0;
|
|
|
|
TQCString cmd;
|
|
|
|
|
|
|
|
target->setLastFetchCount(0);
|
|
|
|
|
|
|
|
sendSignal(TSdownloadNew);
|
|
|
|
errorPrefix=i18n("No new articles could be retrieved for\n%1/%2.\nThe following error occurred:\n")
|
|
|
|
.arg(account.server()).arg(target->groupname());
|
|
|
|
|
|
|
|
cmd="GROUP ";
|
|
|
|
cmd+=target->groupname().utf8();
|
|
|
|
if (!sendCommandWCheck(cmd,211)) { // 211 n f l s group selected
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
currentGroup = target->groupname();
|
|
|
|
|
|
|
|
progressValue = 90;
|
|
|
|
|
|
|
|
s = strchr(getCurrentLine(),' ');
|
|
|
|
if (s) {
|
|
|
|
s++;
|
|
|
|
s = strchr(s,' ');
|
|
|
|
}
|
|
|
|
if (s) {
|
|
|
|
s++;
|
|
|
|
first=atoi(s);
|
|
|
|
target->setFirstNr(first);
|
|
|
|
s = strchr(s,' ');
|
|
|
|
}
|
|
|
|
if (s) {
|
|
|
|
last=atoi(s);
|
|
|
|
} else {
|
|
|
|
TQString tmp=i18n("No new articles could be retrieved.\nThe server sent a malformatted response:\n");
|
|
|
|
tmp+=getCurrentLine();
|
|
|
|
job->setErrorString(tmp);
|
|
|
|
closeConnection();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(target->lastNr()==0) { //first fetch
|
|
|
|
if(first>0)
|
|
|
|
oldlast=first-1;
|
|
|
|
else
|
|
|
|
oldlast=first;
|
|
|
|
} else
|
|
|
|
oldlast=target->lastNr();
|
|
|
|
|
|
|
|
toFetch=last-oldlast;
|
|
|
|
//tqDebug("knode: last %d oldlast %d toFetch %d\n",last,oldlast,toFetch);
|
|
|
|
|
|
|
|
if(toFetch<=0) {
|
|
|
|
//tqDebug("knode: No new Articles in group\n");
|
|
|
|
target->setLastNr(last); // don't get stuck when the article numbers wrap
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(toFetch>target->maxFetch()) {
|
|
|
|
toFetch=target->maxFetch();
|
|
|
|
//tqDebug("knode: Fetching only %d articles\n",toFetch);
|
|
|
|
}
|
|
|
|
|
|
|
|
progressValue = 100;
|
|
|
|
predictedLines = toFetch;
|
|
|
|
|
|
|
|
// get list of additional headers provided by the XOVER command
|
|
|
|
// see RFC 2980 section 2.1.7
|
|
|
|
TQStrList headerformat;
|
|
|
|
cmd = "LIST OVERVIEW.FMT";
|
|
|
|
if ( sendCommand( cmd, rep ) && rep == 215 ) {
|
|
|
|
TQStrList tmp;
|
|
|
|
if (getMsg(tmp)) {
|
|
|
|
for(TQCString s = tmp.first(); !s.isNull(); s = tmp.next()) {
|
|
|
|
s = s.stripWhiteSpace();
|
|
|
|
// remove the mandatory xover header
|
|
|
|
if (s == "Subject:" || s == "From:" || s == "Date:" || s == "Message-ID:"
|
|
|
|
|| s == "References:" || s == "Bytes:" || s == "Lines:")
|
|
|
|
continue;
|
|
|
|
else
|
|
|
|
headerformat.append(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//tqDebug("knode: KNNntpClient::doFetchNewHeaders() : xover %d-%d", last-toFetch+1, last);
|
|
|
|
cmd.sprintf("xover %d-%d",last-toFetch+1,last);
|
|
|
|
if (!sendCommand(cmd,rep))
|
|
|
|
return;
|
|
|
|
|
|
|
|
// no articles in selected range...
|
|
|
|
if (rep==420) { // 420 No article(s) selected
|
|
|
|
target->setLastNr(last);
|
|
|
|
return;
|
|
|
|
} else if (rep!=224) { // 224 success
|
|
|
|
handleErrors();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStrList headers;
|
|
|
|
if (!getMsg(headers)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
progressValue = 1000;
|
|
|
|
sendSignal(TSprogressUpdate);
|
|
|
|
|
|
|
|
sendSignal(TSsortNew);
|
|
|
|
|
|
|
|
mutex.lock();
|
|
|
|
target->insortNewHeaders(&headers, &headerformat, this);
|
|
|
|
target->setLastNr(last);
|
|
|
|
mutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::doFetchArticle()
|
|
|
|
{
|
|
|
|
KNRemoteArticle *target = static_cast<KNRemoteArticle*>(job->data());
|
|
|
|
TQCString cmd;
|
|
|
|
|
|
|
|
sendSignal(TSdownloadArticle);
|
|
|
|
errorPrefix = i18n("Article could not be retrieved.\nThe following error occurred:\n");
|
|
|
|
|
|
|
|
progressValue = 100;
|
|
|
|
predictedLines = target->lines()->numberOfLines()+10;
|
|
|
|
|
|
|
|
if (target->collection()) {
|
|
|
|
TQString groupName = static_cast<KNGroup*>(target->collection())->groupname();
|
|
|
|
if (currentGroup != groupName) {
|
|
|
|
cmd="GROUP ";
|
|
|
|
cmd+=groupName.utf8();
|
|
|
|
if (!sendCommandWCheck(cmd,211)) // 211 n f l s group selected
|
|
|
|
return;
|
|
|
|
currentGroup = groupName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (target->articleNumber() != -1) {
|
|
|
|
cmd.setNum(target->articleNumber());
|
|
|
|
cmd.prepend("ARTICLE ");
|
|
|
|
} else {
|
|
|
|
cmd = "ARTICLE " + target->messageID()->as7BitString(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sendCommandWCheck(cmd,220)) { // 220 n <a> article retrieved - head and body follow
|
|
|
|
int code = atoi(getCurrentLine());
|
|
|
|
if ( code == 430 || code == 423 ) { // 430 no such article found || 423 no such article number in this group
|
|
|
|
TQString msgId = target->messageID()->as7BitString( false );
|
|
|
|
// strip of '<' and '>'
|
|
|
|
msgId = msgId.mid( 1, msgId.length() - 2 );
|
|
|
|
job->setErrorString( errorPrefix + getCurrentLine() +
|
|
|
|
i18n("<br><br>The article you requested is not available on your news server."
|
|
|
|
"<br>You could try to get it from <a href=\"http://groups.google.com/groups?selm=%1\">groups.google.com</a>.")
|
|
|
|
.arg( msgId ) );
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQStrList msg;
|
|
|
|
if (!getMsg(msg))
|
|
|
|
return;
|
|
|
|
|
|
|
|
progressValue = 1000;
|
|
|
|
sendSignal(TSprogressUpdate);
|
|
|
|
|
|
|
|
target->setContent(&msg);
|
|
|
|
target->parse();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::doPostArticle()
|
|
|
|
{
|
|
|
|
KNLocalArticle *art=static_cast<KNLocalArticle*>(job->data());
|
|
|
|
|
|
|
|
sendSignal(TSsendArticle);
|
|
|
|
|
|
|
|
if (art->messageID(false)!=0) {
|
|
|
|
int rep;
|
|
|
|
if (!sendCommand(TQCString("STAT ")+art->messageID(false)->as7BitString(false),rep))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (rep==223) { // 223 n <a> article retrieved - request text separately
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: STAT successful, we have probably already sent this article.");
|
|
|
|
#endif
|
|
|
|
return; // the article is already on the server, lets put it silently into the send folder
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!sendCommandWCheck("POST", 340)) // 340 send article to be posted. End with <CR-LF>.<CR-LF>
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (art->messageID(false)==0) { // article has no message ID => search for a ID in the response
|
|
|
|
TQCString s = getCurrentLine();
|
|
|
|
int start = s.findRev(TQRegExp("<[^\\s]*@[^\\s]*>"));
|
|
|
|
if (start != -1) { // post response includes a recommended id
|
|
|
|
int end = s.find('>',start);
|
|
|
|
art->messageID()->from7BitString(s.mid(start,end-start+1));
|
|
|
|
art->assemble();
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: using the message-id recommended by the server: %s",s.mid(start,end-start+1).data());
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sendMsg(art->encodedContent(true)))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!checkNextResponse(240)) // 240 article posted ok
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::doFetchSource()
|
|
|
|
{
|
|
|
|
KNRemoteArticle *target = static_cast<KNRemoteArticle*>(job->data());
|
|
|
|
|
|
|
|
sendSignal(TSdownloadArticle);
|
|
|
|
errorPrefix = i18n("Article could not be retrieved.\nThe following error occurred:\n");
|
|
|
|
|
|
|
|
progressValue = 100;
|
|
|
|
predictedLines = target->lines()->numberOfLines()+10;
|
|
|
|
|
|
|
|
TQCString cmd = "ARTICLE " + target->messageID()->as7BitString(false);
|
|
|
|
if (!sendCommandWCheck(cmd,220)) // 220 n <a> article retrieved - head and body follow
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQStrList msg;
|
|
|
|
if (!getMsg(msg))
|
|
|
|
return;
|
|
|
|
|
|
|
|
progressValue = 1000;
|
|
|
|
sendSignal(TSprogressUpdate);
|
|
|
|
|
|
|
|
target->setContent(&msg);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool KNNntpClient::openConnection()
|
|
|
|
{
|
|
|
|
currentGroup = TQString();
|
|
|
|
|
|
|
|
TQString oldPrefix = errorPrefix;
|
|
|
|
errorPrefix=i18n("Unable to connect.\nThe following error occurred:\n");
|
|
|
|
|
|
|
|
if (!KNProtocolClient::openConnection())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
progressValue = 30;
|
|
|
|
|
|
|
|
int rep;
|
|
|
|
if (!getNextResponse(rep))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if ( ( rep < 200 ) || ( rep > 299 ) ) { // RFC977: 2xx - Command ok
|
|
|
|
handleErrors();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
progressValue = 50;
|
|
|
|
|
|
|
|
if (!sendCommand("MODE READER",rep))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (rep==500) {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: \"MODE READER\" command not recognized.");
|
|
|
|
#endif
|
|
|
|
} else
|
|
|
|
if ( ( rep < 200 ) || ( rep > 299 ) ) { // RFC977: 2xx - Command ok
|
|
|
|
handleErrors();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
progressValue = 60;
|
|
|
|
|
|
|
|
// logon now, some newsserver send a incomplete group list otherwise
|
|
|
|
if (account.needsLogon() && !account.user().isEmpty()) {
|
|
|
|
//tqDebug("knode: user: %s",account.user().latin1());
|
|
|
|
|
|
|
|
TQCString command = "AUTHINFO USER ";
|
|
|
|
command += account.user().local8Bit();
|
|
|
|
if (!KNProtocolClient::sendCommand(command,rep))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (rep==381) { // 381 PASS required
|
|
|
|
//tqDebug("knode: Password required");
|
|
|
|
|
|
|
|
if (!account.pass().length()) {
|
|
|
|
job->setErrorString(i18n("Authentication failed.\nCheck your username and password."));
|
|
|
|
job->setAuthError(true);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//tqDebug("knode: pass: %s",account.pass().latin1());
|
|
|
|
|
|
|
|
command = "AUTHINFO PASS ";
|
|
|
|
command += account.pass().local8Bit();
|
|
|
|
if (!KNProtocolClient::sendCommand(command,rep))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (rep==281) { // 281 authorization success
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: Authorization successful");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: Authorization failed");
|
|
|
|
#endif
|
|
|
|
job->setErrorString(i18n("Authentication failed.\nCheck your username and password.\n\n%1").arg(getCurrentLine()));
|
|
|
|
job->setAuthError(true);
|
|
|
|
closeConnection();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (rep==281) { // 281 authorization success
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: Authorization successful");
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
if ((rep==482)||(rep==500)) { //482 Authentication rejected
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: Authorization failed"); // we don't care, the server can refuse the info
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
handleErrors();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
progressValue = 70;
|
|
|
|
|
|
|
|
errorPrefix = oldPrefix;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// authentication on demand
|
|
|
|
bool KNNntpClient::sendCommand(const TQCString &cmd, int &rep)
|
|
|
|
{
|
|
|
|
if (!KNProtocolClient::sendCommand(cmd,rep))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (rep==480) { // 480 requesting authorization
|
|
|
|
//tqDebug("knode: Authorization requested");
|
|
|
|
|
|
|
|
if (!account.user().length()) {
|
|
|
|
job->setErrorString(i18n("Authentication failed.\nCheck your username and password."));
|
|
|
|
job->setAuthError(true);
|
|
|
|
closeConnection();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//tqDebug("knode: user: %s",account.user().data());
|
|
|
|
|
|
|
|
TQCString command = "AUTHINFO USER ";
|
|
|
|
command += account.user().local8Bit();
|
|
|
|
if (!KNProtocolClient::sendCommand(command,rep))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (rep==381) { // 381 PASS required
|
|
|
|
//tqDebug("knode: Password required");
|
|
|
|
|
|
|
|
if (!account.pass().length()) {
|
|
|
|
job->setErrorString(i18n("Authentication failed.\nCheck your username and password.\n\n%1").arg(getCurrentLine()));
|
|
|
|
job->setAuthError(true);
|
|
|
|
closeConnection();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//tqDebug("knode: pass: %s",account.pass().data());
|
|
|
|
|
|
|
|
command = "AUTHINFO PASS ";
|
|
|
|
command += account.pass().local8Bit();
|
|
|
|
if (!KNProtocolClient::sendCommand(command,rep))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rep==281) { // 281 authorization success
|
|
|
|
#ifndef NDEBUG
|
|
|
|
tqDebug("knode: Authorization successful");
|
|
|
|
#endif
|
|
|
|
if (!KNProtocolClient::sendCommand(cmd,rep)) // retry the original command
|
|
|
|
return false;
|
|
|
|
} else {
|
|
|
|
job->setErrorString(i18n("Authentication failed.\nCheck your username and password.\n\n%1").arg(getCurrentLine()));
|
|
|
|
job->setAuthError(true);
|
|
|
|
closeConnection();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void KNNntpClient::handleErrors()
|
|
|
|
{
|
|
|
|
if (errorPrefix.isEmpty())
|
|
|
|
job->setErrorString(i18n("An error occurred:\n%1").arg(getCurrentLine()));
|
|
|
|
else
|
|
|
|
job->setErrorString(errorPrefix + getCurrentLine());
|
|
|
|
|
|
|
|
int code = atoi(getCurrentLine());
|
|
|
|
|
|
|
|
// close the connection only when necessary:
|
|
|
|
// 430 no such article found
|
|
|
|
// 411 no such news group
|
|
|
|
// 423 no such article number in this group
|
|
|
|
if ((code != 430)&&(code != 411)&&(code != 423))
|
|
|
|
closeConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//--------------------------------
|
|
|
|
|