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 |