matthew@sunpix.East.Sun.COM (Matthew Stier - Sun Visualization Products) (10/30/90)
New? Yes. Improved? Well I think so. Enclosed is a major revision of the Bnews `recnews' program. I went thru the hassle of revising it after upgrading my site to use an nntp feed, and found out that the mini-inews program provided with nntp does not know command-line arguments. The enclosed shar contains a new recnews.c and new man-page (recnews.8). The old recnews works by stripping the mail header off incoming articles, and feeding the body of the article to inews with command-line arguments for header lines such as "From: ", "Subject: " and "Newsgroups: ". The new recnews works by stripping the mail header, and replacing it with a header constructed of just "From: ", "Subject: ", "Newsgroups: " and "Distribution: " lines. This new header, and the body of the article are feed to inews. ---- Cut Here and unpack ---- #!/bin/sh # shar: Shell Archiver (v1.25) # Packed Mon Oct 29 15:51:29 EST 1990 by matthew@east.sun.com # from directory /home/matthew # # Run the following text with /bin/sh to create: # recnews.8 # recnews.c # echo "x - extracting recnews.8 (Text)" sed 's/^X//' << 'SHAR_EOF' > recnews.8 && X.TH RECNEWS 8 "October 29, 1990" X.SH NAME Xrecnews \- receive unprocessed articles via mail X.SH SYNOPSIS X.BR recnews " [ " X.IR newsgroups " [ " distribution " [ " from " ] ] ] " X.SH DESCRIPTION X.I Recnews Xreads a letter from the standard input; determines the letter's sender, Xsubject, newsgroup and distribution; and feeds the body of the letter, Xwith a new header, to inews for insertion. X.PP XIf X.I newsgroup Xis omitted, the letter's "Newsgroups:" line, and then the "To:" line Xwill be used to determine the destination newsgroup(s). X.I Newsgroups Xmay be a single, or comma seperated line of newsgroups. X.PP XIf X.I distribution Xis omitted, the letter's "Distribution:" line will be used to determine Xthe articles scope of distribution. X.PP XIf X.I from Xis omitted, the letter's "From:" line, and then "From" or ">From" line Xwill be used to determine the originator of the article. X.PP X.SH SEE ALSO Xinews(8), Xsendnews(8), SHAR_EOF chmod 0644 recnews.8 || echo "restore of recnews.8 fails" echo "x - extracting recnews.c (Text)" sed 's/^X//' << 'SHAR_EOF' > recnews.c && X/* X * recnews [newsgroup] [distribution] [from] X * X * Process a news article submitted via mail. Such articles are in X * normal mail format and have never seen the insides of netnews. X * X * If "newsgroup" is included, the article is posted to this newsgroup X * instead of trying to intuit it from the headers. This argument is X * postions dependent. If you want to specify "distribution" or "from" X * and not "newsgroup" this postion will need to be filled with a null X * string. (either "" or '') X * X * If "distribution" is included, the article is posted with this X * distribution, vice the distribution listed in the article header. X * This argument is postions dependent. If you want to specify "from" X * and not "distribution" this postion will need to be filled with a null X * string. (either "" or '') X * X * If "from" is included, the return address is forged to look like that X * user instead of what the "From:" line says. X * X * It is recommended that you always include the "newsgroup", since the X * intuition code can be flakey. The "from" is probably appropriate X * in some circumstances to control e-mail replies. X * X * Sample lines in /etc/aliases X * X * worldnews: "|/usr/lib/news/recnews general" X * Allows you to mail to worldnews rather than using inews. X * Intended for humans to mail to. X * X * post-unix-wizards: "|/usr/lib/news/recnews ba.unix-wizards ba" X * Causes mail to post-unix-wizards to be fed into ba.unix-wizards X * and the distribution limited to 'ba'. X * X * in-gamemasters: "|/usr/lib/news/recnews mail.gamemasters '' dm" X * Causes mail to in-gamemasters to be fed into mail.gamemasters X * and the return address to be changed to user 'dm'. X * X * Recnews is primarily useful in remote places on the usenet which collect X * mail from mailing lists and funnel them into the network. It is also X * useful if you like to submit articles by e-mail (Many mailers give X * you nice facilities for editing the message.) It is not, however, X * essential to use recnews to be able to join usenet. X * X * WARNING: recnews disables the "recording" check - it has to because X * by the time inews is run, it's in the background and too late to X * ask permission. If you depend heavily on recordings you probably X * should not allow recnews (and thus the mail interface) to be used. X * X * 1) The from, to and subject lines are left alone - except for double quotes X * and backslashes which are escaped to protect them from shell parsing X * 2) We give precedence to "From:" over "From" or ">From" in determining X * who the article is really from. X * X * Modifications by rad@tek X * X * mstier@east.sun.com: (02/09/90) X * fixed the double_quote_at_end_of_line and unprotected backslash X * problems. fixed error that assumed a minimum length of data read X * by fgets(). removed optional third and fourth arguments added by X * John@ODU.EDU, and pleasant@rutgers; recnews now passes all other X * command-line arguments to inews. consolidated redundant code and X * stripped unnecessary code. X * X * mstier@east.sun.com: (10/29/90) X * fixed recnews to work with the nntp mini-inews. another large X * change to direct feed the header as part of the article, vice X * command-line arguments. X * X */ X X/* X * mstier@sun.com: (02/09/90) X * A major hack of recnews.c not really v2.20 anymore, (may be 2.30, X * or 3.00) but I don't control the revision number. X * mstier@sun.com: (02/09/90) X * ditto X * X * static char *SccsId = "@(#)recnews.c 2.20 1/17/89"; X */ X X#ifdef SCCSID Xstatic char *SccsId = "@(#)recnews.c mstier@sun.com ?.?? 10/29/90"; X#endif /* SCCSID */ X X#include "params.h" X X/* X * Note: we assume there are 2 kinds of hosts using recnews: X * Those that have delivermail (and hence this program will never X * have to deal with more than one message at a time) and those on the arpanet X * that do not (and hence all messages end with a sentinel). It is X * supposed that regular v7 type systems without delivermail or some X * other automatic forwarding device will just use rnews. We do X * not attempt to tell where a message ends on all systems due to the X * different conventions in effect. (This COULD be fixed, I suppose.) X */ X X/* X * Function declarations X */ Xint main(); Xint type(); Xvoid argcpy(); XFILE *pipeopen(); Xint pipeclose(); X X/* X * Kinds of lines in a message. X */ X#define TO 0 /* To: line */ X#define FROM 1 /* From: line */ X#define SENDER 2 /* From line */ X#define SUBJECT 3 /* Subject: line */ X#define NEWSGROUPS 4 /* Newsgroups: line */ X#define DISTRIBUTION 5 /* Distribution: line */ X#define HEADER 6 /* any unrecognized header */ X#define BLANK 7 /* blank line */ X#define TEXT 8 /* anything unrecognized */ X#define EOM 9 /* End of message (4 ctrl A's) */ X X/* X * Define 'state' and possible states program can be in. X */ X#define SKIPPING 1 /* In header of message */ X#define READING 2 /* In body of message */ X X#define BFSZ 256 X X#define EOT '\004' X X/* X * Header buffers X */ Xchar to[BFSZ]; Xchar from[BFSZ]; Xchar sender[BFSZ]; Xchar subject[BFSZ]; Xchar newsgroups[BFSZ]; Xchar distribution[BFSZ]; X Xextern char *strcat(), *strcpy(), *strpbrk(), *strchr(), *sprintf(); X Xint Xmain(argc, argv) Xint argc; Xchar **argv; X{ X char buf[BFSZ], inews[BFSZ]; X FILE *pipe = NULL; X int state; X X X /* build inews command */ X#ifdef LOGDIR X (void)sprintf(inews, "%s/%s/%s", logdir(HOME), LIBDIR, "inews -h"); X#else /* !LOGDIR */ X (void)sprintf(inews, "%s/%s", LIBDIR, "inews -h"); X#endif /* !LOGDIR */ X X /* Parse the command-line args */ X if (argc > 1 && argv[1][0]) X (void)strcpy(newsgroups, argv[1]); X else X (void)strcpy(newsgroups, ""); X X if (argc > 2 && argv[2][0]) X (void)strcpy(distribution, argv[2]); X else X (void)strcpy(distribution, ""); X X if (argc > 3 && argv[3][0]) X (void)strcpy(from, argv[3]); X else X (void)strcpy(from,""); X X /* Initialize the remaining buffers */ X (void)strcpy(to, ""); X (void)strcpy(sender, ""); X (void)strcpy(subject, ""); X X /* Parse the article */ X state = SKIPPING; X while (fgets(buf, BFSZ, stdin) != NULL) { X if (state == READING) { X fputs(buf,pipe); X continue; X } X switch (type(buf)) { X X case TO: X if (!to[0]) X argcpy(to, buf, 3); X break; X X case FROM: X if (!from[0]) X argcpy(from, buf, 5); X break; X X case SENDER: X if (!sender[0]) X argcpy(sender, buf, 4); X break; X X case SUBJECT: X if (!subject[0]) X argcpy(subject, buf, 8); X break; X X case NEWSGROUPS: X if (!newsgroups[0]) X argcpy(newsgroups, buf, 11); X break; X X case DISTRIBUTION: X if (!distribution[0]) X argcpy(distribution, buf, 13); X break; X X case HEADER: X break; X X case BLANK: X state = BLANK; X case TEXT: X#ifdef debug X pipe = stdout; X#else X pipe = pipeopen(inews); X if (pipe == NULL) { X perror("recnews: pipeopen failed"); X exit(1); X } X#endif X (void)fprintf(pipe, "From: %s\n", X from[0] ? from : sender); X (void)fprintf(pipe, "Subject: %s\n", X subject[0] ? subject : "(none)"); X (void)fprintf(pipe, "Newsgroups: %s\n", X newsgroups[0] ? newsgroups : to); X (void)fprintf(pipe, "Distribution: %s\n", X distribution[0] ? distribution : ""); X if (state != BLANK) X fputs(buf,pipe); X state = READING; X break; X } X } X (void)pipeclose(pipe); X exit(0); X /*NOTREACHED*/ X} X X/* X * What type of line was just read by 'fgets()'. X * X */ Xint Xtype(p) Xregister char *p; X{ X char *firstbl; X static char lasthdr = 1; /* prev line was a header */ X X if ((*p == ' ' || *p == '\t') && lasthdr) X return(HEADER); /* continuation line */ X firstbl = strpbrk(p, " \t"); X while (*p == ' ' || *p == '?' || *p == '\t') X ++p; X X if (*p == '\n' || *p == 0) X return(BLANK); X if (STRNCMP(p, "To", 2)==0) X return(TO); X if (STRNCMP(p, "From:", 5) == 0) X return(FROM); X if (STRNCMP(p, ">From", 5) == 0 || STRNCMP(p, "From", 4) == 0) X return(SENDER); X if (STRNCMP(p, "Subject:", 8) == 0 || STRNCMP(p, "Subj", 4) == 0 || X STRNCMP(p, "Re:", 3) == 0 || STRNCMP(p, "re:", 3) == 0) X return(SUBJECT); X if (STRNCMP(p, "Distribution:", 13)==0) X return(DISTRIBUTION); X if (STRNCMP(p, "\1\1\1\1", 4)==0) X return(EOM); X if (firstbl && firstbl[-1] == ':' && isalpha(*p)) X return(HEADER); X lasthdr = 0; X return(TEXT); X} X X/* X * Copy the src to dest, modifying as necessary. X * X */ Xvoid Xargcpy(dest, src, index) Xchar *dest; Xchar *src; Xint index; X{ X char *orig_src = src; X char *orig_dest = dest; X X /* Search for the first whitespace */ X while (*src != ' ' && *src != '\t' && *src != NULL) X src++; X X /* Search for the next non-whitespace */ X while (*src == ' ' || *src == '\t') X src++; X X /* If whitespace not found, use index and guess at start of line */ X if (src == NULL) X if (strlen(orig_src) > index) X src = orig_src + index; X else X src = orig_src + strlen(src); X X /* Copy the src to the dest adding backspaces where needed */ X do { X if (*src == '"' || *src == '\\') X *dest++ = '\\'; X } while (*dest++ = *src++); X X /* and null terminate the string */ X if (src = strchr(orig_dest, '\n')) X *src = '\0'; X} X X/* X * This is similar to popen(), but made more secure. Rather X * than forking off a shell, you get a bare process. X * You can use "" to get white space into an argument, but X * nothing else is recognized X */ X X#define RDR 0 X#define WTR 1 X#define MAXARGS 20 Xstatic int mopen_pid[20]; X XFILE * Xpipeopen(cmd) Xregister char *cmd; X{ X int p[2]; X register myside, hisside, pid; X X if(pipe(p) < 0) X return(NULL); X myside = p[WTR]; X hisside = p[RDR]; X if ((pid = vfork()) == 0) { X char *args[MAXARGS]; X register char **ap = args; X X /* myside and hisside reverse roles in child */ X (void) close(myside); X (void) close(0); X (void) dup(hisside); X (void) close(hisside); X (void) setgid(getgid()); X (void) setuid(getuid()); X X while (isspace(*cmd)) X cmd++; X X while (*cmd != '\0') { X *ap++ = cmd; X if (ap >= &args[MAXARGS]) { X (void)fprintf(stderr, "Too many args to %s", X args[0]); X _exit(2); X } X while (*cmd && !isspace(*cmd)) { X if (*cmd++ == '"') { X register char *bcp = cmd-1; X while (*cmd) { X if(*cmd == '\\') { X cmd++; X } else if (*cmd == '"') X break; X *bcp++ = *cmd++; X } X *bcp = '\0'; X cmd++; X } X } X if (*cmd) X *cmd++ = '\0'; X while (isspace(*cmd)) X cmd++; X } X *ap = (char *)NULL; X X execv(args[0], args); X perror("pipeopen exec:"); X _exit(1); X } X X if(pid == -1) X return(NULL); X X mopen_pid[myside] = pid; X (void) close(hisside); X return(fdopen(myside, "w")); X} X X/* X * Close the pipe opened by 'pipeopen()'. X * X */ Xint Xpipeclose(ptr) XFILE *ptr; X{ X register int f, r; X SIGNAL_TYPE hstat, istat, qstat; X int status; X X f = fileno(ptr); X (void) fclose(ptr); X istat = signal(SIGINT, SIG_IGN); X qstat = signal(SIGQUIT, SIG_IGN); X hstat = signal(SIGHUP, SIG_IGN); X while((r = wait(&status)) != mopen_pid[f] && r != -1) X ; X if(r == -1) X status = -1; X (void)signal(SIGINT, istat); X (void)signal(SIGQUIT, qstat); X (void)signal(SIGHUP, hstat); X return(status); X} X SHAR_EOF chmod 0755 recnews.c || echo "restore of recnews.c fails" exit 0 -- Matthew Lee Stier (mstier@east.Sun.COM) | Sun Microsystems --- RTP, NC 27709-3447 | "Wisconsin Escapee" uucp: sun!mstier or mcnc!rti!sunpix!matthew | phone: (919) 469-8300 fax: (919) 460-8355 |