|
|
BSD 4.3
#ifndef lint
static char *sccsid = "@(#)newnews.c 1.5 (Berkeley) 3/20/86";
#endif
#include "common.h"
long gmt_to_local();
/*
* 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)
int argc;
char *argv[];
{
char *cp, *ngp;
char *key;
char datebuf[32];
char line[MAX_STRLEN];
char **distlist, **nglist, **histlist;
int distcount, ngcount, histcount;
int all;
FILE *fp;
long date;
long dtol();
char *ltod();
if (argc < 4) {
printf("%d NEWNEWS requires at least three arguments.\r\n",
ERR_CMDSYN);
(void) fflush(stdout);
return;
}
all = streql(argv[1], "*");
if (!all) {
ngcount = get_nglist(&nglist, argv[1]);
if (ngcount == 0) {
printf("%d Bogus newsgroup specifier: %s\r\n",
ERR_CMDSYN);
(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 (streql(*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;
}
}
fp = fopen(HISTORY_FILE, "r");
if (fp == NULL) {
syslog(LOG_ERR, "newnews: fopen %s: %m", HISTORY_FILE);
printf("%d Cannot open history file.\r\n", ERR_FAULT);
(void) fflush(stdout);
return;
}
printf("%d New news by message id follows.\r\n", OK_NEWNEWS);
if (seekuntil(fp, key, line, sizeof (line)) < 0) {
printf(".\r\n");
(void) fflush(stdout);
(void) fclose(fp);
return;
}
/*
* History file looks like:
*
* <[email protected]> 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(nglist, ngcount, histlist, histcount))
continue;
if (distcount)
if (!distmatch(distlist, distcount, histlist, histcount))
continue;
*cp = '\0';
printf("%s\r\n", line);
} while (fgets(line, sizeof(line), fp) != NULL);
printf(".\r\n");
(void) fflush(stdout);
(void) fclose(fp);
}
/*
* 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, key, line, linesize)
FILE *fp;
char *key;
char *line;
int linesize;
{
char datetime[32];
int c;
long top, bot, mid;
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);
}
getword(fp, w, line, linesize)
FILE *fp;
char *w;
char *line;
int linesize;
{
register char *cp;
if (fgets(line, linesize, fp) == NULL)
return (0);
if (cp = index(line, '\t')) {
/*
* The following gross hack is present because the history file date
* format is braindamaged. They like "mm/dd/yy hh:mm", which is useless
* for relative comparisons of dates using something like atoi() or
* strcmp. So, this changes their format into yymmddhhmm. Sigh.
*
* 12345678901234 ("x" for cp[x])
* mm/dd/yy hh:mm (their lousy representation)
* yymmddhhmm (our good one)
* 0123456789 ("x" for w[x])
*/
*cp = '\0';
(void) strncpy(w, cp+1, 15);
w[0] = cp[7]; /* Years */
w[1] = cp[8];
w[2] = cp[1]; /* Months */
w[3] = cp[2];
w[4] = cp[4]; /* Days */
w[5] = cp[5];
w[6] = cp[10]; /* Hours */
w[7] = cp[11];
w[8] = cp[13]; /* Minutes */
w[9] = cp[14];
w[10] = '\0';
} else
w[0] = '\0';
return (1);
}
/*
* ngmatch -- match a list of newsgroups, with possible wildcard
* expansion (i.e., *) with a list of newsgroups.
* Both the newsgroups we're to match against (regexps) and
* the list of newsgroups for this line in the history file are
* in argc/argv format.
*
* Parameters: "nglist" is the list of group specifiers to match
* against.
* "ngcount" is the number of groups in nglist.
* "matchlist" is the list of newsgroups to match against.
* "matchcount" is number of groups in matchlist.
*
* Returns: 1 if the named newsgroup is in the list.
* 0 otherwise.
*
* Side effects: Terminates \n on end of grlist.
*
* Note: This ain't the same routine as "ngmatch"
* in the normal news software, although it
* probably should be.
*/
ngmatch(nglist, ngcount, matchlist, matchcount)
char **nglist;
int ngcount;
char **matchlist;
int matchcount;
{
int i, j;
int match;
register char *cp;
match = 0;
for (i = 0; i < matchcount; ++i) {
if (cp = index(matchlist[i], '/'))
*cp = '\0';
for (j = 0; j < ngcount; ++j) {
if (nglist[j][0] == '!') { /* Handle negation */
if (restreql(nglist[j]+1, matchlist[i]))
return (0); /* Hit a matching '!' */
} else {
if (restreql(nglist[j], matchlist[i]))
match = 1;
}
}
}
return (match);
}
/*
* restreql -- regular expression string equivalnce routine,
* but not really full fledged. Thanks and a tip of the hat to
* Nick Lai, <[email protected]> for this time saving device.
*
* Parameters: "w" is an asterisk-broadened regexp,
* "s" is a non-regexp string.
* Returns: 1 if match, 0 otherwise.
*
* Side effects: None.
*/
restreql(w, s)
register char *w;
register char *s;
{
while (*s && *w) {
switch (*w) {
case '*':
for (w++; *s; s++)
if (restreql(w, s))
return 1;
break;
default:
if (*w != *s)
return 0;
w++, s++;
break;
}
}
if (*s)
return 0;
while (*w)
if (*w++ != '*')
return 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.
* "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 *cp;
register FILE *fp;
register int i, j;
char buf[MAX_STRLEN];
fp = fopen(grouplist[0], "r");
if (fp == NULL) {
syslog(LOG_ERR, "distmatch: fopen %s: %m", buf);
return (0);
}
while (fgets(buf, sizeof (buf), fp) != NULL) {
cp = index(buf, '\n');
if (cp)
*cp = '\0';
if (buf[0] == '\0') /* End of header */
break;
cp = index(buf, ':');
if (cp == NULL)
continue;
*cp = '\0';
if (streql(buf, "distribution")) {
for (i = 0; i < distcount; ++i) {
if (streql(cp + 2, distlist[i])) {
(void) fclose(fp);
return (1);
}
}
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; ++i)
if (streql(grouplist[i], distlist[i]))
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;
static char **ng_list = (char **) NULL;
for (cp = list; *cp != '\0'; ++cp)
if (*cp == ',')
*cp = ' ';
ngcount = parsit(list, &ng_list);
*array = ng_list;
return (ngcount);
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.