home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.5
/
ffcollection-1-5-1992-11.iso
/
ff_disks
/
300-399
/
ff319.lzh
/
CNewsSrc
/
cnews.orig.lzh
/
nntpdiffs
/
src
/
newnews.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-06-27
|
11KB
|
515 lines
#ifndef lint
static char *sccsid = "@(#)newnews.c 1.19 (Berkeley) 2/6/88";
#endif
#include "common.h"
#include "time.h"
#ifdef LOG
int nn_told = 0;
int nn_took = 0;
#endif
/*
* NEWNEWS newsgroups date time ["GMT"] [<distributions>]
*
* Return the message-id's of any news articles past
* a certain date and time, within the specified distributions.
*
*/
newnews(argc, argv)
register int argc;
char *argv[];
{
register char *cp, *ngp;
char *key;
char datebuf[32];
char line[MAXBUFLEN];
char **distlist, **histlist;
static char **nglist;
int distcount, ngcount, histcount;
int all;
FILE *fp;
long date;
long dtol();
char *ltod();
#ifdef USG
FILE *tmplst;
int i;
char *tmpfile;
#endif USG
if (argc < 4) {
printf("%d Usage: NEWNEWS newsgroups yymmdd hhmmss [\"GMT\"] [<distributions>
.\r\n",
ERR_CMDSYN);
(void) fflush(stdout);
return;
}
#ifdef LOG
sprintf(line, "%s newnews %s %s %s %s %s",
hostname,
argv[1],
argv[2],
argv[3],
(argc >= 5 && *argv[4] == 'G') ? "GMT" : "local",
(argc >= 5 && *argv[argc-1] == '<') ? argv[argc-1] : "none");
syslog(LOG_INFO, line);
#endif
all = (argv[1][0] == '*' && argv[1][1] == '\0');
if (!all) {
ngcount = get_nglist(&nglist, argv[1]);
if (ngcount == 0) {
printf("%d Bogus newsgroup specifier: %s\r\n",
ERR_CMDSYN, argv[1]);
(void) fflush(stdout);
return;
}
}
/* YYMMDD HHMMSS */
if (strlen(argv[2]) != 6 || strlen(argv[3]) != 6) {
printf("%d Date/time must be in form YYMMDD HHMMSS.\r\n",
ERR_CMDSYN);
(void) fflush(stdout);
return;
}
(void) strcpy(datebuf, argv[2]);
(void) strcat(datebuf, argv[3]);
argc -= 4;
argv += 4;
/*
* Flame on. The history file is not stored in GMT, but
* in local time. So we have to convert GMT to local time
* if we're given GMT, otherwise we need only chop off the
* the seconds. Such braindamage.
*/
key = datebuf; /* Unless they specify GMT */
if (argc > 0) {
if (!strcasecmp(*argv, "GMT")) { /* Which we handle here */
date = dtol(datebuf);
if (date < 0) {
printf("%d Invalid date specification.\r\n",
ERR_CMDSYN);
(void) fflush(stdout);
return;
}
date = gmt_to_local(date);
key = ltod(date);
++argv;
--argc;
}
}
/* So, key now points to the local time, but we need to zap secs */
key[10] = '\0';
distcount = 0;
if (argc > 0) {
distcount = get_distlist(&distlist, *argv);
if (distcount < 0) {
printf("%d Bad distribution list: %s\r\n", ERR_CMDSYN,
*argv);
(void) fflush(stdout);
return;
}
}
#ifdef USG
if ((tmpfile = mktemp("/tmp/listXXXXXX")) == NULL ||
(tmplst = fopen(tmpfile, "w+")) == NULL) {
printf("%d Cannot process history file.\r\n", ERR_FAULT);
(void) fflush(stdout);
return;
}
for (i = 0; i < 9; i++) {
sprintf(historyfile, "%s.d/%d", HISTORY_FILE, i);
#endif USG
fp = fopen(historyfile, "r");
if (fp == NULL) {
#ifdef SYSLOG
syslog(LOG_ERR, "newnews: fopen %s: %m", historyfile);
#endif
#ifndef USG
printf("%d Cannot open history file.\r\n", ERR_FAULT);
(void) fflush(stdout);
return;
#else USG
continue;
#endif USG
}
#ifndef USG
printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
#endif not USG
if (seekuntil(fp, key, line, sizeof (line)) < 0) {
#ifndef USG
printf(".\r\n");
(void) fflush(stdout);
#endif not USG
(void) fclose(fp);
#ifndef USG
return;
#else USG
continue;
#endif USG
}
/*
* History file looks like:
*
* <1569@emory.UUCP> 01/22/86 09:19 net.micro.att/899 ucb.general/2545
* ^--tab ^--tab ^--space ^sp\0
* Sometimes the newsgroups are missing; we try to be robust and
* ignore such bogosity. We tackle this by our usual parse routine,
* and break the list of articles in the history file into an argv
* array with one newsgroup per entry.
*/
do {
if ((cp = index(line, '\t')) == NULL)
continue;
if ((ngp = index(cp+1, '\t')) == NULL) /* 2nd tab */
continue;
++ngp; /* Points at newsgroup list */
if (*ngp == '\n')
continue;
histcount = get_histlist(&histlist, ngp);
if (histcount == 0)
continue;
/*
* For each newsgroup on this line in the history
* file, check it against the newsgroup names we're given.
* If it matches, then see if we're hacking distributions.
* If so, open the file and match the distribution line.
*/
if (!all)
if (!ngmatch(restreql, 0, nglist, ngcount,
histlist, histcount))
continue;
if (distcount)
if (!distmatch(distlist, distcount, histlist, histcount))
continue;
*cp = '\0';
#ifdef USG
fputs(line, tmplst);
fputc('\n', tmplst);
#else not USG
putline(line);
#endif not USG
#ifdef LOG
nn_told++;
#endif
} while (fgets(line, sizeof(line), fp) != NULL);
#ifndef USG
putchar('.');
putchar('\r');
putchar('\n');
(void) fflush(stdout);
#endif
(void) fclose(fp);
#ifdef USG
}
printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
rewind(tmplst);
while (fgets(line, sizeof(line), tmplst) != NULL)
putline(line);
putchar('.');
putchar('\r');
putchar('\n');
(void) fflush(stdout);
(void) fclose(tmplst);
(void) unlink(tmpfile);
#endif USG
}
/*
* seekuntil -- seek through the history file looking for
* a line with date "key". Get that line, and return.
*
* Parameters: "fp" is the active file.
* "key" is the date, in form YYMMDDHHMM (no SS)
* "line" is storage for the first line we find.
*
* Returns: -1 on error, 0 otherwise.
*
* Side effects: Seeks in history file, modifies line.
*/
seekuntil(fp, akey, line, linesize)
FILE *fp;
char *akey;
char *line;
int linesize;
{
char datetime[32];
register int c;
register long top, bot, mid;
extern long dtol();
char key[30];
(void) sprintf(key, "%ld", dtol(akey)); /* akey -> time_t in ascii */
bot = 0;
(void) fseek(fp, 0L, 2);
top = ftell(fp);
for(;;) {
mid = (top+bot)/2;
(void) fseek(fp, mid, 0);
do {
c = getc(fp);
mid++;
} while (c != EOF && c!='\n');
if (!getword(fp, datetime, line, linesize)) {
return (-1);
}
switch (compare(key, datetime)) {
case -2:
case -1:
case 0:
if (top <= mid)
break;
top = mid;
continue;
case 1:
case 2:
bot = mid;
continue;
}
break;
}
(void) fseek(fp, bot, 0);
while(ftell(fp) < top) {
if (!getword(fp, datetime, line, linesize)) {
return (-1);
}
switch(compare(key, datetime)) {
case -2:
case -1:
case 0:
break;
case 1:
case 2:
continue;
}
break;
}
return (0);
}
compare(s, t)
register char *s, *t;
{
for (; *s == *t; s++, t++)
if (*s == 0)
return(0);
return (*s == 0 ? -1:
*t == 0 ? 1:
*s < *t ? -2:
2);
}
/*
* C news version of getword.
*/
getword(fp, w, line, linesize)
FILE *fp;
register char *w;
char *line;
int linesize;
{
register char *cp;
extern char *index();
if (fgets(line, linesize, fp) == NULL)
return (0);
w[0] = '\0'; /* in case of bad format */
if (cp = index(line, '\t')) { /* find 2nd field */
register char *endp;
*cp++ = '\0';
endp = index(cp, '~'); /* end of date-received */
if (endp == NULL)
endp = index(cp, '\t'); /* end of expiry */
if (endp != NULL) {
(void) strncpy(w, cp, endp - cp);
w[endp - cp] = '\0';
}
}
return (1);
}
/*
* distmatch -- see if a file matches a set of distributions.
* We have to do this by (yech!) opening the file, finding
* the Distribution: line, if it has one, and seeing if the
* things match.
*
* Parameters: "distlist" is the distribution list
* we want.
* "distcount" is the count of distributions in it.
* "grouplist" is the list of groups (articles)
* for this line of the history file. Note that
* this isn't quite a filename.
* "groupcount" is the count of groups in it.
*
* Returns: 1 if the article is in the given distribution.
* 0 otherwise.
*/
distmatch(distlist, distcount, grouplist, groupcount)
char *distlist[];
int distcount;
char *grouplist[];
int groupcount;
{
register char c;
register char *cp;
register FILE *fp;
register int i, j;
char buf[MAXBUFLEN];
(void) strcpy(buf, spooldir);
(void) strcat(buf, "/");
(void) strcat(buf, grouplist[0]);
for (cp = buf; *cp; cp++)
if (*cp == '.')
*cp = '/';
fp = fopen(buf, "r");
if (fp == NULL) {
#ifdef SYSLOG
syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
#endif
return (0);
}
while (fgets(buf, sizeof (buf), fp) != NULL) {
if ((c = buf[0]) == '\n') /* End of header */
break;
if (c != 'd' && c != 'D')
continue;
cp = index(cp + 1, '\n');
if (cp)
*cp = '\0';
cp = index(buf, ':');
if (cp == NULL)
continue;
*cp = '\0';
if (!strcasecmp(buf, "distribution")) {
for (i = 0; i < distcount; ++i) {
if (!strcasecmp(cp + 2, distlist[i])) {
(void) fclose(fp);
return (1);
}
}
(void) fclose(fp);
return (0);
}
}
(void) fclose(fp);
/*
* We've finished the header with no distribution field.
* So we'll assume that the distribution is the characters
* up to the first dot in the newsgroup name.
*/
for (i = 0; i < groupcount; i++) {
cp = index(grouplist[i], '.');
if (cp)
*cp = '\0';
for (j = 0; j < distcount; j++)
if (!strcasecmp(grouplist[i], distlist[j]))
return (1);
}
return (0);
}
/*
* get_histlist -- return a nicely set up array of newsgroups
* (actually, net.foo.bar/article_num) along with a count.
*
* Parameters: "array" is storage for our array,
* set to point at some static data.
* "list" is the history file newsgroup list.
*
* Returns: Number of group specs found.
*
* Side effects: Changes static data area.
*/
get_histlist(array, list)
char ***array;
char *list;
{
register int histcount;
register char *cp;
static char **hist_list = (char **) NULL;
cp = index(list, '\n');
if (cp)
*cp-- = '\0';
histcount = parsit(list, &hist_list);
*array = hist_list;
return (histcount);
}
/*
* get_nglist -- return a nicely set up array of newsgroups
* along with a count, when given an NNTP-spec newsgroup list
* in the form ng1,ng2,ng...
*
* Parameters: "array" is storage for our array,
* set to point at some static data.
* "list" is the NNTP newsgroup list.
*
* Returns: Number of group specs found.
*
* Side effects: Changes static data area.
*/
get_nglist(array, list)
char ***array;
char *list;
{
register char *cp;
register int ngcount;
for (cp = list; *cp != '\0'; ++cp)
if (*cp == ',')
*cp = ' ';
ngcount = parsit(list, array);
return (ngcount);
}