2.9BSD/usr/contrib/notes/bnewsinput.c
static char *sccsid = "@(#)bnewsinput.c 1.2 2/2/83";
#include <sys/types.h>
#include "parms.h"
#include "structs.h"
#include "globs.h"
#include "newsgate.h"
#include "bnews.h"
/*
* bnewsinput.c
*
* This program will accept an article according the the
* 'B' protocol for news(I). The article will then be inserted in
* the notefile(s) which match the newsgroup(s).
*
* Modified April 1982:
* The newer version is somewhat more streamlined.
* So, the other major difference in the new version is that if the
* title is of the form:
* some title - (nf)
* (or if the suffix is "- (nf)"
* we decide that it has been generated by notesfiles. This means that
* we are allowed to skip text up to a # and then we have a special
* ALMOST generic notesfile format. The header information is
* slightly different.
* see canon.h for the new format examples
*
* Original Coding: Ray Essick Feb 1982
* Modified extensively: Ray Essick April 1982
* Modified to add some neat things
* Malcolm Slaney July 1982
* added code to catch misformed articles
* Ray Essick July 27, 1982
* Modified to add even more neat things
* Rick L Spickelmier, UCB 1982
* Added the B news parser and multiple groups
* Rick L Spickelmier
*
*/
extern char longtitle[WDLEN]; /* storage for titles longer the TITLEN */
#define min(A,B) ((A) > (B) ? (B) : (A))
main (argc, argv)
int argc;
char **argv;
{
struct io_f io;
char title[TITLEN + 40]; /* title */
char nf[NNLEN]; /* the notefile */
char fname[WDLEN]; /* hold scratch file name */
char ngroup[WDLEN][NUMGROUPS]; /* newsgroups name */
char fromsys[SYSSZ],
origsys[SYSSZ];
char *p,
*q,
*r;
char *suffix;
int count,
atcount, /* count ARPA hosts */
status;
int c;
int i,
j,
stat,
length, /* of title */
notenum;
struct note_f note;
struct note_f note2;
struct auth_f auth;
long newsseq;
struct id_f respid;
struct when_f entered,
whentime;
struct id_f newsid;
char line[CMDLEN]; /* scratch */
struct daddr_f where;
FILE *rawnews; /* raw news read from here */
FILE *scr; /* scratch file for holding article */
FILE *hread();
struct hbuf *hp;
#include "main.i" /* common init code and such */
rawnews = stdin; /* read from the right file */
/* Parse the header */
hp = (struct hbuf *) malloc(sizeof(struct hbuf));
rawnews = hread(hp, rawnews);
/* get origsys and newsseq */
sscanf(hp->ident,"%[^.].%ld",origsys,&newsseq);
/* get the fromsys and author line */
strcpy(line,hp->path);
/* parse the path */
i = strlen(line); /* start at rhs */
for (j = 0; j < i; j++)
if (line[j] == ' ')
break;
while (j && (line[j] != '!') && (line[j] != ':') && (line[j] != '.')) {
j--; /* back to sys */
}
atcount = 0; /* count ARPA hosts parsed */
if (j == 0) j = -1;
for (i = 0, j++; (i < NAMESZ); i++) {
if ((auth.aname[i] = line[j + i]) == '@' && atcount++) {
auth.aname[i] = '\0';
break; /* only parse 1 ARPA host */
} else {
if (auth.aname[i] == ' ') {
auth.aname[i] = '\0'; /* null terminate */
break; /* and get out of here */
} else {
if (auth.aname[i] == 0) {
break;
}
}
}
}
/* build the from system */
for (i = 0; (i < SYSSZ - 1) && line[i] != '!' && line[i] != ':' && line[i] != '.'; i++) {
fromsys[i] = line[i];
}
fromsys[i] = '\0';
/* get the title and longtitle */
strcpy(longtitle,hp->title);
strncpy(title,longtitle,TITLEN+39);
strcat(longtitle,"\n\n");
title[min(TITLEN+39,strlen(longtitle))] = '\0';
/* get the date */
getdate(hp->subdate,&entered);
/* get the newsgroups */
sscanf(hp->nbuf,"%[^,\n]",ngroup[0]);
/*
* The header is now parsed, all left is text.
* Check existence of the notesfile, permission
* to write and other things like that
*/
newsgroup (ngroup[0], nf, NEWSNF); /* alias the bugger */
if (init(&io, nf) < 0) { /* well is it there? */
printf("Non-existant notesfile: %s\n", nf);
#ifdef AUTOCREATE
/* try to create the notes file - RLS */
sprintf(line,"%s/%s/mknf -on %s",MSTDIR,UTILITY,nf);
system(line);
if (init(&io, nf) < 0) {
sprintf(line, "notesfile: %s, newsgroup %s\n", ngroup[0], nf);
nfcomment(NOSUCHWARN, line, "Failure", 0, 0);
exit(BAD);
}
sprintf(line, "Created: %s\n", nf);
nfcomment(NOSUCHWARN, line, line, 0, 0);
#else
sprintf(line, "notesfile: %s, newsgroup %s\n", ngroup[0], nf);
nfcomment(NOSUCHWARN, line, "Failure", 0, 0);
exit(BAD);
#endif
}
if ((io.descr.d_stat & NETWRKD) == 0) { /* networked ? */
printf("Notesfile %s is not networked\n", nf);
exit (BAD);
}
r = q = title;
while (*r) { /* look for last '-' */
if (*r == '-') {
q = r; /* this is new last */
}
r++; /* on to the next */
}
suffix = q; /* save the pointer for possible later use */
/* like misformed articles with "- (nf)" */
length = q - title; /* non-nulls before '-' */
if (strcmp(q, NFSUFFIX) != 0 && strcmp(q, OLDSUFFIX) != 0) {
/* so is not nf generated */
/*
* we come back up to here if the article had the notesfile
* suffix and was not properly formatted.
* This is a stopgap measure due to the fact that I misdesigned
* the system so that notes used a right associative rule
* to determine its articles, while news programs used a
* left associative rule. Oh well.
* - Ray Essick July 27, 1982
*/
badform: /* come here if no "#" in a "- (nf)" article */
getperms(&io, 1, origsys);
if (allow(&io, WRITOK) == 0) {
printf("System %s not allowed to write notes\n", origsys);
exit (BAD);
}
strmove(origsys, newsid.sys); /* build uniq id */
newsid.uniqid = (-newsseq * 100) - 1;
/* is not there yet */
strmove(origsys, note.n_id.sys);
note.n_id.uniqid = (-100 * newsseq); /* build the note descriptor */
copydate(&entered, ¬e.n_date);
strmove(fromsys, note.n_from);
stat = FRMNEWS; /* came from news system */
i = 0; /* fix up the title */
while (title[i++]); /* get to the end */
for (i--; i < TITLEN; i++) {
title[i] = ' '; /* space pad */
}
lock(&io, 'n');
if ((notenum = chknote (&io, ¬e.n_id, ¬e2)) == 0) {
if (!strncmp (title, "Re:", 3)) { /* see if a "followup" */
p = title;
do {
p += 3;
while (*p == ' ')
p++; /* Skip Spaces */
} while (!strncmp (p, "Re:", 3)); /* get all re's */
strcpy(io.xstring, p);
notenum = findtitle(&io, io.descr.d_nnote);
if (notenum > 0 && !chkresp(&io, &newsid, ¬e2, notenum)) {
longtitle[0] = '\0';
pagein(&io, rawnews, &where);
gettime(&whentime);
putresp(&io, &where, stat, notenum, &entered, &auth,
¬e, NOLOCKIT, &newsid, NOADDID, fromsys, ADDTIME,
&whentime);
} else {
if (notenum < 1) {
pagein(&io, rawnews, &where);
notenum = putnote(&io, &where, title, stat, ¬e, &auth,
NOPOLICY, NOLOCKIT, NOADDID, fromsys, ADDTIME);
io.nnotrcvd++; /* count as networked in */
} else {
printf("Duplicate Response handed back by news\n");
}
}
} else {
pagein(&io, rawnews, &where);
notenum = putnote(&io, &where, title, stat, ¬e, &auth,
NOPOLICY, NOLOCKIT, NOADDID, fromsys, ADDTIME);
io.nnotrcvd++; /* count as networked in */
}
} else if (note2.n_stat & ORPHND) { /* replace foster parent */
pagein(&io, rawnews, ¬e2.n_addr); /* collect text */
gettime(¬e2.n_rcvd); /* current tod */
gettime(¬e2.n_lmod); /* last touched */
copyauth(&auth, ¬e2.n_auth); /* fill in the author */
note2.n_stat |= FRMNEWS; /* brand it */
for (i = 0; i < TITLEN; i++) {
note2.ntitle[i] = title[i]; /* move new title */
}
copydate(&entered, ¬e2.n_date); /* written date */
strcpy(note2.n_from, fromsys); /* and who gave it to us */
putnrec(&io, notenum, ¬e2); /* and replace */
} else {
printf("Duplicate news article received\n");
}
unlock(&io, 'n');
} else { /* nf generated article */
sprintf(fname, "/tmp/nfn%d", getpid ()); /* generate name */
scr = fopen(fname, "w"); /* open scratch file */
while ((c = getc(rawnews)) != '#' && c != EOF) { /* find start */
if (scr != NULL) {
putc(c, scr); /* hold it in the scratch file */
}
}
if (c == EOF) {
fclose(scr); /* flush what is there */
if ((rawnews = fopen(fname, "r")) == NULL) {
printf("Article lost in file system: %s\n", fname);
unlink(fname); /* remove the file */
closenf(&io); /* close the notesfile */
exit(BAD);
}
*--suffix = '\0'; /* remove " - (nf)" suffix */
unlink(fname); /* only link is the file descriptor */
goto badform; /* reparse as a news article */
}
fclose(scr); /* close and */
unlink(fname); /* toss the scratch file */
switch (getc(rawnews)) {
case 'N': /* base note coming through news */
if (fscanf(rawnews, ":%[^:]:%ld:%o:%d", note.n_id.sys,
¬e.n_id.uniqid, &status, &count) != 4)
goto toobad; /* bad form */
while (getc(rawnews) != '\n'); /* skip eol */
for (i = length; i < TITLEN; i++) {
title[i] = ' '; /* space fill */
}
/* skip sys name, got elsewhere */
while ((c = getc(rawnews)) != '!');
for (i = 0; (i < NAMESZ - 1) && ((c = getc (rawnews)) != ' '); i++)
auth.aname[i] = c; /* get the author */
i = 0;
while ((line[i] = getc(rawnews)) != '\n');
/* grab date */
getdate(line, ¬e.n_date);
/* loop in case trash on line */
/* in theory this line is empty */
while (getc(rawnews) != '\n');
getperms(&io, 1, note.n_id.sys); /* see if he's allowed */
if (allow(&io, WRITOK) == 0) { /* not a chance */
closenf(&io);
exit(BAD);
}
lock(&io, 'n');
if ((notenum = chknote(&io, ¬e.n_id, ¬e2)) == 0) {
/* is it there? */
pagein(&io, rawnews, &where); /* grab text */
status |= FRMNEWS; /* came through news! */
strmove(fromsys, note.n_from);
putnote(&io, &where, title, status, ¬e, &auth, NOPOLICY,
NOLOCKIT, NOADDID, fromsys, ADDTIME);
io.nnotrcvd++; /* count it */
} else {
if ((note2.n_stat & ORPHND) && NOT (status & ORPHND)) {
/* extant is orphan, new isnt */
pagein(&io, rawnews, ¬e2.n_addr);
/* grab text */
gettime(¬e2.n_rcvd);
gettime(¬e2.n_lmod); /* time stamp it */
copyauth(&auth, ¬e2.n_auth);
/* put correct author */
note2.n_stat = status + FRMNEWS;
/* correct status */
for (i = 0; i < TITLEN; i++) {
note2.ntitle[i] = title[i];
}
copydate(&entered, ¬e2.n_date);
strmove(fromsys, note2.n_from);
putnrec(&io, notenum, ¬e2); /* and replace */
} else { /* duplicate */
printf("Duplicate note handed back by news\n");
}
}
unlock(&io, 'n');
break;
case 'R': /* response coming through news */
if (fscanf(rawnews, ":%[^:]:%ld:%[^:]:%ld:%o:%d", note.n_id.sys,
¬e.n_id.uniqid, respid.sys, &respid.uniqid, &status, &count) != 6)
goto toobad; /* bad form */
while (getc(rawnews) != '\n'); /* skip eol */
getperms(&io, 1, respid.sys); /* see if he's allowed */
if (allow(&io, RESPOK) == 0) { /* not a chance */
closenf(&io);
exit(BAD);
}
/* skip sys name, got elsewhere */
while ((c = getc(rawnews)) != '!');
for (i = 0; (i < NAMESZ - 1) && ((c = getc(rawnews)) != ' '); i++)
auth.aname[i] = c; /* get the author */
i = 0;
/* grab date */
while ((line[i] = getc(rawnews)) != '\n');
getdate(line, &entered);
/* loop in case trash on line */
/* in theory this line is empty */
while (getc(rawnews) != '\n');
lock(&io, 'n');
notenum = chknote(&io, ¬e.n_id, ¬e2);
if (notenum == 0) { /* build foster parent */
printf("Orphaned response handed in by news\n");
strmove(fromsys, note.n_from);
note.n_nresp = 0;
note.n_auth.aid = ANONUID;
strcpy(note.n_auth.aname, "Unknown");
copydate(&entered, ¬e.n_date);
gettime(&whentime); /* get current time */
status = ORPHND + FRMNEWS; /* combo there */
for (i = 0, p = "Orphaned Response"; (i < TITLEN) && *p; p++, i++)
note.ntitle[i] = *p;
for (; i < TITLEN; i++) {
note.ntitle[i] = ' '; /* pad */
}
where.addr = 0; /* no text */
notenum = putnote(&io, &where, note.ntitle, status,
¬e, ¬e.n_auth, NOPOLICY, NOLOCKIT,
NOADDID, fromsys, ADDTIME);
io.norphans++; /* census of orphans */
getnrec(&io, notenum, ¬e2); /* get good one */
}
if (chkresp(&io, &respid, ¬e2, notenum) == 0) {
/* none, insert it */
longtitle[0] = '\0';
status |= FRMNEWS;
pagein(&io, rawnews, &where);
putresp(&io, &where, status, notenum, &entered, &auth,
¬e, NOLOCKIT, &respid, NOADDID, fromsys, ADDTIME, &whentime);
io.nrsprcvd++; /* count him in */
} else {
printf("Duplicate response handed back by news\n");
}
unlock(&io, 'n');
break;
default: /* bad news coming through news */
toobad: /* label for bad format jumps */
printf("Some sort of failure caused jump to toobad\n");
closenf(&io);
exit(BAD);
}
} /* end of nf coming back in */
lock(&io, 'n');
getdscr(&io, &io.descr);
io.descr.netwrkins++; /* count as net in */
putdscr(&io, &io.descr);
unlock(&io, 'n');
finish(&io);
exit(GOOD);
}