/*******************************************************************************
Copyright (c) 1994,1995 William Pemberton (wfp5p@virginia.edu)
The X Consortium, and any party obtaining a copy of these files from
the X Consortium, directly or indirectly, is granted, free of charge, a
full and unrestricted irrevocable, world-wide, paid up, royalty-free,
nonexclusive right and license to deal in this software and
documentation files (the "Software"), including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons who receive
copies from any such party to do so. This license includes without
limitation a license to do the foregoing actions under any patents of
the party supplying this software to the X Consortium.
*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <varargs.h>
#include <errno.h>
#include <sys/stat.h>
#include "xbuffy.h"
#define CR (13)
#define LF LINEFEED
#define NEWLINE LF
#define CHUNK_SIZE (1024L)
#define MAX_LINE (1024)
#ifdef TESTNEWS
FILE *NNTP_fIn, *NNTP_fOut;
int NNTPinit = 0;
#else
extern FILE *NNTP_fIn, *NNTP_fOut;
extern int NNTPinit;
#endif
void Fatal(va_alist)
{
char *fmt;
extern int errno;
va_list p;
va_start(p);
fmt = va_arg(p, char *);
vfprintf(stderr, fmt, p);
fputc('\n', stderr);
if (errno)
perror("System error");
va_end(p);
exit(1);
}
void fputeol(FILE * NNTP_fOut)
{
fputc(CR, NNTP_fOut);
fputc(LF, NNTP_fOut);
fflush(NNTP_fOut);
}
void initNNTP()
{
char line[1024];
int err;
int sock;
char *serverName;
struct sockaddr_in server;
struct hostent *hp;
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
Fatal("socket failed");
server.sin_family = AF_INET;
server.sin_port = htons(119); /* NNTP */
serverName = getenv("NNTPSERVER");
if (serverName == NULL)
#ifdef NNTP_SERVER
serverName = NNTP_SERVER;
#else
Fatal("Please set $NNTPSERVER to an appropriate news server.");
#endif
hp = gethostbyname(serverName);
if (hp == 0)
Fatal("gethostbyname failed");
bcopy(*hp->h_addr_list, (char *) &server.sin_addr, hp->h_length);
err = connect(sock, (struct sockaddr*)&server, sizeof(server));
if (err)
Fatal("connect failed");
if (!(NNTP_fIn = fdopen(sock, "r")))
Fatal("fdopen(sock,\"r\") failed");
if (!(NNTP_fOut = fdopen(sock, "w")))
Fatal("fdopen(sock,\"w\") failed");
/* get header line */
fgets(line, sizeof(line), NNTP_fIn);
if (atoi(line) != 200)
Fatal("initial line unexpected: %s", line);
NNTPinit = 1;
}
int getHeaders(long Article, char **from, char **subject)
{
char line[CHUNK_SIZE];
char *q;
int x;
fprintf(NNTP_fOut, "head %ld", Article);
fputeol(NNTP_fOut);
if (fgets(line, sizeof(line) - 1, NNTP_fIn) == 0)
Fatal("getHeaders: premature EOF");
if ((x = atoi(line)) != 221)
{
if (x == 423) /* then the article just don't exist */
return (0);
else
Fatal("getHeaders: got a bad value: %s", line);
}
while ((line[0] != '.') && (line[1] != NEWLINE))
{
/* retrieve line */
if (fgets(line, sizeof(line) - 1, NNTP_fIn) == 0)
Fatal("ReadBlock: premature EOF");
/* look for CR LF at the end of the line then replace it with NEWLINE */
q = line + NEWstrlen(line) - 1;
#ifdef DEBUG
if (q[0] != LF)
Fatal("ReadBlock: didn't find LF at end-of-line:\n%s", line);
if (q[-1] != CR)
Fatal("ReadBlock: didn't see CR near end-of-line:\n%s", line);
#endif
q[-1] = NEWLINE;
if (strincmp(line, "From:", 5) == 0)
*from = strdup(line);
if (strincmp(line, "Subject:", 8) == 0)
*subject = strdup(line);
}
return (1);
}
static char *getNewsrc()
{
static char fname[512];
sprintf(fname, "%s/.newsrc", getenv("HOME"));
return (fname);
}
void readNewsrcEntry(newsBox, firstArt, lastArt)
BoxInfo_t *newsBox;
long firstArt;
long lastArt;
{
FILE *newsrc;
Boolean done = FALSE;
char line[MAX_LINE];
static Articles_t tempArt;
newsrc = fopen(getNewsrc(), "r");
if (newsrc == NULL)
Fatal("Can't open .newsrc\n");
while (DynSize(newsBox->articles))
DynDelete(newsBox->articles, DynHigh(newsBox->articles));
while ((!done) && (fgets(line, MAX_LINE - 1, newsrc) != 0))
{
char *tmp;
char *backp;
if (strincmp(line, newsBox->box, NEWstrlen(newsBox->box)) != 0)
continue;
tmp = line + NEWstrlen(newsBox->box);
while ((!isdigit(*tmp)) && (*tmp != '\n'))
tmp++;
backp = tmp;
while (*tmp != '\n')
{
/* First number */
while (isdigit(*tmp))
{
tmp++;
}
tempArt.firstNum = atol(backp);
backp = tmp;
/* Is that it or is there another? */
if (*tmp == ',')
{
tempArt.lastNum = tempArt.firstNum;
tmp++;
backp++;
}
else if (*tmp == '\n')
{
tempArt.lastNum = tempArt.firstNum;
}
/* There IS more */
else
{
tmp++;
backp++;
while (isdigit(*tmp))
{
tmp++;
}
tempArt.lastNum = atol(backp);
backp = tmp;
if (*tmp != '\n')
{
tmp++, backp++;
}
}
if (tempArt.lastNum > firstArt)
{
if (tempArt.firstNum < firstArt)
tempArt.firstNum = firstArt;
DynAdd(newsBox->articles, &tempArt);
}
}
}
fclose(newsrc);
tempArt.firstNum = tempArt.lastNum = lastArt + 1;
DynAdd(newsBox->articles, &tempArt);
}
int insideBox(x, firstNum, lastNum)
long x;
long firstNum;
long lastNum;
{
return ((x >= firstNum) && (x <= lastNum));
}
int CountNNTP(newsBox, headerString, beenTouched)
BoxInfo_t *newsBox;
DynObject headerString;
Boolean *beenTouched;
{
char line[1024];
char *from;
char *subject;
long firstArticle;
long lastArticle;
long retVal;
long count;
long numberArticles;
long x;
int index;
struct stat f_stat;
Articles_t *artP;
if (!NNTPinit)
initNNTP();
*beenTouched = FALSE;
count = 0;
/* send dummy group selection */
/* fputs("group news.answers", NNTP_fOut);
fputeol(NNTP_fOut); */
/* get return line */
/* fgets(line, sizeof(line), NNTP_fIn);
if (atoi(line) != 211)
Fatal("unexpected response to group line: %s", line);*/
/* send group selection */
sprintf(line, "group %s", newsBox->box);
fputs(line, NNTP_fOut);
fputeol(NNTP_fOut);
#ifdef DEBUG
printf("countNNTP: send %s\n",line);
#endif
/* get return line */
fgets(line, sizeof(line), NNTP_fIn);
if (atoi(line) != 211)
Fatal("unexpected response to group line: %s", line);
if (4 != sscanf(line, "%ld %ld %ld %ld", &retVal, &numberArticles, &firstArticle, &lastArticle))
Fatal("couldn't parse group line: %s", line);
#ifdef DEBUG
printf("countNNTP: read %s\n",line);
#endif
stat(getNewsrc(), &f_stat);
if ((f_stat.st_size != newsBox->st_size) ||
(f_stat.st_mtime > newsBox->box_mtime))
{
newsBox->st_size = f_stat.st_size;
newsBox->box_mtime = f_stat.st_mtime;
*beenTouched = TRUE;
}
readNewsrcEntry(newsBox, firstArticle, lastArticle);
#ifdef DEBUG
len = DynLow(newsBox->articles);
while (len <= DynHigh(newsBox->articles))
{
artP = (Articles_t *) DynGet(newsBox->articles, len);
printf("Pair %ld %ld\n", artP->firstNum, artP->lastNum);
len++;
}
#endif
artP = (Articles_t *) DynGet(newsBox->articles, 0);
index = 0;
x = firstArticle;
while (x <= lastArticle)
{
if (!insideBox(x, artP[index].firstNum, artP[index].lastNum))
{
from = subject = NULL;
if (getHeaders(x, &from, &subject))
{
count++;
if (headerString != NULL)
{
from[NEWstrlen(from) - 1] = subject[NEWstrlen(subject) - 1] = '\0';
DynInsert(headerString, ((DynHigh(headerString) > 0) ? (DynHigh(headerString) + 1) : 0), from, NEWstrlen(from));
DynInsert(headerString, ((DynHigh(headerString) > 0) ? (DynHigh(headerString) + 1) : 0), subject, NEWstrlen(subject));
}
free(from);
free(subject);
}
}
else
{
x = artP[index].lastNum;
index++;
}
x++;
}
return (count);
}
#ifdef TESTNEWS
void main()
{
BoxInfo_t tempBox;
Boolean dummy;
tempBox.articles = DynCreate(sizeof(Articles_t), 2);
while (1)
{
DynObject headers;
char *hdrPtr;
headers = DynCreate(sizeof(char), MAX_STRING);
tempBox.box = "uva.general";
printf("There are %i articles\n", CountNNTP(&tempBox, NULL, &dummy));
CountNNTP(&tempBox, headers, &dummy);
DynAdd(headers, '\0');
hdrPtr = (char *) DynGet(headers, 0);
printf("\n*********************\n%s\n", hdrPtr);
printf("done\n");
sleep(20);
}
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1