/*
* FEED.C
*
* Feed-related NNTP commands.
*
* (c)Copyright 1998, Matthew Dillon, All Rights Reserved. Refer to
* the COPYRIGHT file in the base directory of this distribution
* for specific rights granted.
*/
#include "defs.h"
Prototype void NNTPMode(Connection *conn, char **pptr);
Prototype void NNTPIHave(Connection *conn, char **pptr);
Prototype void NNTPCheck(Connection *conn, char **pptr);
Prototype void NNTPTakeThis(Connection *conn, char **pptr);
Prototype void NNTPPost(Connection *conn, char **pptr);
Prototype int ValidXRef(const char *buf, int len);
void NNAcceptArticleStart(Connection *conn, const char *msgid);
void NNAcceptArticle(Connection *conn);
/*
* mode stream
* mode reader
* mode headfeed
*/
void
NNTPMode(Connection *conn, char **pptr)
{
char *mode = parseword(pptr, " \t");
int ok = 0;
if (mode) {
if (strcasecmp(mode, "stream") == 0) {
conn->co_Flags |= COF_STREAM;
MBLogPrintf(conn, &conn->co_TMBuf, "203 StreamOK.\r\n");
ok = 1;
}
if (strcasecmp(mode, "headfeed") == 0) {
if (conn->co_Flags & COF_SERVER) {
conn->co_Flags |= COF_HEADFEED;
MBLogPrintf(conn, &conn->co_TMBuf, "250 Mode Command OK.\r\n");
} else {
MBLogPrintf(conn, &conn->co_TMBuf, "500 Mode Command Failed, no server access.\r\n");
}
ok = 1;
}
if (strcasecmp(mode, "reader") == 0) {
if (conn->co_Auth.dr_Flags & DF_FEEDONLY) {
MBLogPrintf(conn, &conn->co_TMBuf, "500 Mode Command Failed, feed-only connection.\r\n");
ok = 1;
} else {
if (conn->co_Flags & COF_SERVER) {
/*
* Once out of server mode, you cant get back in and
* the reader-mode flags apply.
*/
conn->co_Flags &= ~COF_SERVER;
}
NNWriteHello(conn);
return;
}
}
}
if (ok == 0)
MBLogPrintf(conn, &conn->co_TMBuf, "500 Syntax error or bad command\r\n");
NNCommand(conn);
}
/*
*
*/
void
NNTPIHave(Connection *conn, char **pptr)
{
if (conn->co_Flags & COF_SERVER) {
const char *origmsgid = "<>";
const char *msgid = MsgId(parseword(pptr, ""), &origmsgid);
if (strcmp(msgid, "<>") == 0) {
MBLogPrintf(conn, &conn->co_TMBuf, "435 %s Bad Message-ID\r\n",
origmsgid);
NNCommand(conn);
return;
}
conn->co_Flags &= ~(COF_IHAVE|COF_POST|COF_POSTTOOBIG);
conn->co_Flags |= COF_IHAVE;
MBLogPrintf(conn, &conn->co_TMBuf, "335\r\n");
NNAcceptArticleStart(conn, msgid);
} else {
MBLogPrintf(conn, &conn->co_TMBuf, "480 Transfer permission denied\r\n");
NNCommand(conn);
}
}
void
NNTPCheck(Connection *conn, char **pptr)
{
const char *origmsgid = "<>";
const char *msgid = MsgId(parseword(pptr, " \t"), &origmsgid);
if (conn->co_Flags & COF_SERVER) {
if (strcmp(msgid, "<>") == 0)
MBLogPrintf(conn, &conn->co_TMBuf, "438 %s\r\n", origmsgid);
else
MBLogPrintf(conn, &conn->co_TMBuf, "238 %s\r\n", msgid);
} else {
MBLogPrintf(conn, &conn->co_TMBuf, "500 What?\r\n");
}
NNCommand(conn);
}
void
NNTPTakeThis(Connection *conn, char **pptr)
{
const char *origmsgid = "<>";
const char *msgid = MsgId(parseword(pptr, ""), NULL);
conn->co_Flags &= ~(COF_IHAVE|COF_POST|COF_POSTTOOBIG);
if (conn->co_Flags & COF_SERVER) {
if (strcmp(msgid, "<>") == 0) {
MBLogPrintf(conn, &conn->co_TMBuf, "439 %s\r\n", origmsgid);
NNCommand(conn);
} else
NNAcceptArticleStart(conn, msgid);
} else {
MBLogPrintf(conn, &conn->co_TMBuf, "500 What?\r\n");
NNCommand(conn);
}
}
void
NNTPPost(Connection *conn, char **pptr)
{
char *rcode;
char *rdesc;
if (conn->co_Auth.dr_Flags & DF_POST) {
conn->co_Flags &= ~(COF_IHAVE|COF_POST);
conn->co_Flags |= COF_POST;
GenerateMessageID(conn);
#ifdef POST_FORCEMSGID
rcode = "345";
rdesc = "(forced)";
#else
rcode = "340";
rdesc = "(desired)";
#endif
MBLogPrintf(conn, &conn->co_TMBuf, "340 %s %s %s\r\n",
rcode, conn->co_IHaveMsgId, rdesc);
NNAcceptArticleStart(conn, NULL);
} else {
MBLogPrintf(conn, &conn->co_TMBuf, "440 Posting Not Allowed.\r\n");
NNCommand(conn);
}
}
void
NNAcceptArticleStart(Connection *conn, const char *msgid)
{
if (msgid) {
if (conn->co_IHaveMsgId)
zfreeStr(&conn->co_MemPool, &conn->co_IHaveMsgId);
conn->co_IHaveMsgId = zallocStr(&conn->co_MemPool, msgid);
}
conn->co_Flags |= COF_INHEADER;
conn->co_Flags &= ~COF_WASCONTROL;
conn->co_Flags |= COF_MAYNOTCLOSE;
conn->co_ByteCounter = 0.0;
conn->co_BytesHeader = 0;
MBFree(&conn->co_ArtBuf);
NNAcceptArticle(conn);
}
void
NNAcceptArticle(Connection *conn)
{
char *buf;
int len;
int maxl = 1000;
conn->co_Func = NNAcceptArticle;
conn->co_State = "accart";
while ((len = MBReadLine(&conn->co_RMBuf, &buf)) > 0 && --maxl > 0) {
/*
* expected EOF, ".\r\n", but we also allow ".\n" because some
* idiotic newsreaders (like old versions of netscape) don't do the
* right thing.
*/
if ((len == 3 && strcmp(buf, ".\r") == 0) ||
(len == 2 && strcmp(buf, ".") == 0)
) {
if (conn->co_Flags & COF_HEADFEED) /* can't use bytecounter */
conn->co_ByteCounter = 0.0;
if (conn->co_Flags & COF_POST) {
NNPostBuffer(conn);
} else {
NNFeedOverview(conn);
}
conn->co_Flags &= ~COF_MAYNOTCLOSE;
return;
}
/*
* We normally unescape dots, but if this article reception is for
* a POST command we leave them intact so we do not have to
* re-escape them when the article buffer is passed on.
*/
if ((conn->co_Flags & COF_POST) == 0) {
if (len > 0 && buf[0] == '.') {
++buf;
--len;
}
}
/*
* end of headers ?
* control message ?
*/
if (conn->co_Flags & COF_INHEADER) {
char ch = tolower(*buf);
if (strcmp(buf, "\r") == 0) {
conn->co_Flags &= ~COF_INHEADER;
} else if (ch == 'b' && strncasecmp(buf, "Bytes:", 6) == 0) {
/*
* save received Bytes: header (for header-only feed), but
* do not write the header out.
*/
conn->co_BytesHeader = strtol(buf + 6, NULL, 10);
len = 0;
} else if (ch == 'c' && strncasecmp(buf, "Control:", 8) == 0) {
conn->co_Flags |= COF_WASCONTROL;
} else if (ch == 'x' && strncasecmp(buf, "Xref:", 5) == 0) {
/*
* strip XRef: unless it's one we want
*/
if (ValidXRef(buf, len) < 0)
len = 0;
}
}
/*
* buffer the article, but don't bother buffering the article body
* for a fed article. BUT, if it's a Control: message, we need the
* whole body so we can pgp-verify it
*/
conn->co_Auth.dr_PostBytes += len;
conn->co_ByteCounter += len;
if (DOpts.ReaderMaxArtSize > 0 && conn->co_ArtBuf.mh_Bytes > DOpts.ReaderMaxArtSize)
conn->co_Flags |= COF_POSTTOOBIG;
else if ((conn->co_Flags & COF_INHEADER) || (conn->co_Flags & (COF_POST|COF_WASCONTROL))) {
if (len > 0)
buf[len-1] = '\n';
MBWrite(&conn->co_ArtBuf, buf, len);
}
}
if (len <= 0) {
if (len < 0)
NNTerminate(conn);
} else {
/*
* more lines were pending, wake us up immediately, after we've
* processed some other people.
*/
FD_SET(conn->co_Desc->d_Fd, &WFds);
}
}
/*
* Return 0 on success, -1 if XRefSlaveHost is disabled, -2
* If the XRef is invalid.
*/
int
ValidXRef(const char *buf, int len)
{
/*
* strip XRef: unless it's one we want
*/
int l;
int lp;
const char *p;
if (DOpts.ReaderXRefSlaveHost == NULL)
return(-1);
l = strlen(DOpts.ReaderXRefSlaveHost);
p = buf + 5;
lp = len - 5;
while (lp > 0 && *p == ' ') {
--lp;
++p;
}
if (lp <= l ||
strncasecmp(DOpts.ReaderXRefSlaveHost, p, l) != 0 ||
p[l] != ' '
) {
return(-2);
}
return(0);
}
syntax highlighted by Code2HTML, v. 0.9.1