DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T r

⟦c7fa0289d⟧ TextFile

    Length: 10845 (0x2a5d)
    Types: TextFile
    Names: »recnews.c«

Derivation

└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
    └─⟦373604645⟧ »EurOpenD3/news/bnews.2.11/src.tar.Z« 
        └─⟦3beb569ac⟧ 
            └─⟦this⟧ »src/recnews.c« 

TextFile

/*
 * recnews [to newsgroup] [from user] [approved by] [exclude site]
 *
 * Process a news article which has been mailed to some group like msgs.
 * Such articles are in normal mail format and have never seen the insides
 * of netnews.  If the "to newsgroup" is included, the article is posted
 * to this newsgroup instead of trying to intuit it from the headers.
 * If the "from user" is included, the return address is forged to look
 * like that user instead of what getuid or a from line says.
 *
 * It is recommended that you always include the to newsgroup, since the
 * intuition code is flakey and out of date.  The from user is probably
 * appropriate for arpanet mailing lists being funnelled at ucbvax but
 * not otherwise.  Sample lines in /usr/lib/aliases (if you run delivermail):
 *	worldnews: "|/usr/lib/news/recnews net.general"
 *		Allows you to mail to worldnews rather than using inews.
 *		Intended for humans to mail to.
 *	post-unix-wizards: "|/usr/lib/news/recnews fa.unix-wizards unix-wizards"
 *		Causes mail to post-unix-wizards to be fed into fa.unix-wizards
 *		and the return address forged as unix-wizards on the local
 *		machine.  post-unix-wizards (on the local machine) should
 *		be part of the master mailing list somewhere (on a different
 *		machine.)
 *	in-gamemasters: "|/usr/lib/news/recnews mail.gamemasters '' news"
 *
 * Recnews is primarily useful in remote places on the usenet which collect
 * mail from mailing lists and funnel them into the network.  It is also
 * useful if you like to send mail to some user instead of invoking
 * inews -t .. -n .. when you want to submit an article.  (Many mailers give
 * you nice facilities like editing the message.)  It is not, however,
 * essential to use recnews to be able to join usenet.
 *
 * WARNING: recnews disables the "recording" check - it has to because
 * by the time inews is run, it's in the background and too late to
 * ask permission.  If you depend heavily on recordings you probably
 * should not allow recnews (and thus the mail interface) to be used.
 *
 * 1) We leave the from line alone.  Just escape the double quotes, but let the
 *    mailer do the rest.
 * 2) We give precedence to "From:" over "From " or ">From " in determining
 *    who the article is really from.
 *    Modifications by rad@tek
 *
 * John@ODU.EDU: add third argument to cause inews to be invoked with -a,
 *		 for use with local groups for mailing lists with 2.11.
 * pleasant@rutgers.EDU: add fourth argument which uses the -x switch in inews
 *
 */

#ifdef SCCSID
static char	*SccsId = "@(#)recnews.c	2.20	1/17/89";
#endif /* SCCSID */

#include "params.h"

/*
 * Note: we assume there are 2 kinds of hosts using recnews:
 * Those that have delivermail (and hence this program will never
 * have to deal with more than one message at a time) and those on the arpanet
 * that do not (and hence all messages end with a sentinel).  It is
 * supposed that regular v7 type systems without delivermail or some
 * other automatic forwarding device will just use rnews.  We do
 * not attempt to tell where a message ends on all systems due to the
 * different conventions in effect.  (This COULD be fixed, I suppose.)
 */

/*
 * Kinds of lines in a message.
 */
#define FROM	001		/* From line */
#define SUBJ	002		/* Subject */
#define TO	003		/* To (newgroup based on this) */
#define BLANK	004		/* blank line */
#define EOM	005		/* End of message (4 ctrl A's) */
#define HEADER	006		/* any unrecognized header */
#define TEXT	007		/* anything unrecognized */
#define INCLUSIVE 010		/* newsgroup is already in header */

/*
 * Possible states program can be in.
 */
#define SKIPPING	0100	/* In header of message */
#define READING		0200	/* In body of message */

#define BFSZ 250

#define EOT	'\004'

char	from[BFSZ];		/* mailing address for replies */
char	sender[BFSZ];		/* mailing address of author, if different */
char	to[BFSZ];		/* Destination of mail (msgs, etc) */
char	subject[BFSZ];		/* subject of message */
char	newsgroup[BFSZ];	/* newsgroups of message */
char	approved[BFSZ];		/* Approved: */
char	not_this_site[BFSZ];	/* Don't post to this site */
int	fromset;		/* from passed on command line */
char	cmdbuf[BFSZ];		/* command to pipeopen */

extern	char	*strcat(), *strcpy(), *index();
FILE	*pipeopen();
char	*any();

main(argc, argv)
int argc;
char **argv;
{
	char buf[BFSZ], inews[BFSZ];
	register char *p, *q;
	register FILE *pipe = NULL;
	register int state;

	/* build inews command */
#ifdef LOGDIR
	sprintf(inews, "%s/%s/%s", logdir(HOME), LIBDIR, "inews");
#else	/* !LOGDIR */
	sprintf(inews, "%s/%s", LIBDIR, "inews");
#endif	/* !LOGDIR */

	if (argc > 1)
		strcpy(to, argv[1]);
	if (argc > 2)
		strcpy(from, argv[2]);
	if (argc > 3 && *argv[3]) {
		sprintf(approved," -a \"%s\"", argv[3]);
	} else
		approved[0] = '\0';
	if (argc > 4 && *argv[4]) {
		sprintf(not_this_site, " -x \"%s\"", argv[4]);
	} else
		not_this_site[0] = '\0';

	/*
	 * Flag that we know who message is from to avoid trying to 
	 * decipher the From line.
	 */
	if (argc > 2 && (argv[2][0] != '\0'))
		fromset++;

#ifdef debug
	printf("argv[0] is <%s>, argv[1] is <%s>, argv[2] is <%s>\n",
		argv[0], argv[1], argv[2]);
#endif
	state = SKIPPING;
	while (fgets(buf, BFSZ, stdin) != NULL) {
		if (state == READING) {
			fputs(buf,pipe);
			continue;
		}
		switch (type(buf)) {

		case FROM:
			frombreak(buf, from);
			break;

		case SUBJ:
			p = any(buf, " \t");
			if (p == NULL)
				p = buf + 8;
			q = subject;
			while (*++p) {
				if (*p == '"')
					*q++ = '\\';
				*q++ = *p;
			}
			q[-1] = '\0';
			break;

		case TO:
			if (to[0])
				break;		/* already have one */
			p = any(buf, " \t");
			if (p == NULL)
				p = buf + 3;
			q = to;
			while (*++p) {
				if (*p == '"')
					*q++ = '\\';
				*q++ = *p;
			}
			q[-1] = '\0';
			break;

		case INCLUSIVE:
			sprintf(cmdbuf,"%s%s -p", inews, not_this_site);
			pipe = pipeopen(cmdbuf);
			if (pipe == NULL){
				perror("recnews: open failed");
				exit(1);
			}
			state = READING;
			fputs(buf,pipe);
			break;
			
		/*
		 * Kludge to compensate for messages without real headers
		 */
		case HEADER:
			break;

		case BLANK:
			state = READING;
			strcpy(newsgroup, to);
			sprintf(cmdbuf,
				"%s -t \"%s\" -n \"%s\" -f \"%s\"%s%s",
				inews, *subject ? subject : "(none)",
				newsgroup, from, approved, not_this_site);
#ifdef debug
			pipe = stdout;
			printf("BLANK: %s\n", cmdbuf);
#else
			pipe = pipeopen(cmdbuf);
			if (pipe == NULL) {
				perror("recnews: pipeopen failed");
				exit(1);
			}
#endif
			if (sender[0]) {
				fputs(sender, pipe);
				putc('\n', pipe);
			}
			break;

		case TEXT:
			strcpy(newsgroup, to);
			state = READING;
			if (subject[0] == 0) {
				strcpy(subject, buf);
				if (subject[strlen(subject)-1] == '\n')
					subject[strlen(subject)-1] = '\0';
			}
			sprintf(cmdbuf,
				"%s -t \"%s\" -n \"%s\" -f \"%s\"%s%s",
				inews, subject, newsgroup, from, approved,
				not_this_site);
#ifdef debug
			pipe = stdout;
			printf("TEXT: %s\n", cmdbuf);
#else
			pipe = pipeopen(cmdbuf);
			if (pipe == NULL) {
				perror("pipe failed");
				exit(1);
			}
#endif
			if (sender[0]){
				fputs(sender, pipe);
				putc('\n',pipe);
			}
			break;
		}
	}
	pipeclose(pipe);
	exit(0);
	/*NOTREACHED*/
}

type(p)
register char *p;
{
	char *firstbl;
	static char lasthdr = 1;		/* prev line was a header */

	if ((*p == ' ' || *p == '\t') && lasthdr)
		return HEADER;		/* continuation line */
	firstbl = any(p, " \t");
	while (*p == ' ' || *p == '?' || *p == '\t')
		++p;

	if (*p == '\n' || *p == 0)
		return BLANK;
	if (STRNCMP(p, ">From", 5) == 0 || STRNCMP(p, "From", 4) == 0)
		return FROM;
	if (STRNCMP(p, "Subj", 4)==0 || STRNCMP(p, "Re:", 3)==0 ||
		STRNCMP(p, "re:", 3)==0)
		return SUBJ;
	if (STRNCMP(p, "To", 2)==0)
		return TO;
	if (STRNCMP(p, "\1\1\1\1", 4)==0)
		return EOM;
	if (firstbl && firstbl[-1] == ':' && isalpha(*p))
		return HEADER;
	lasthdr = 0;
	return TEXT;
}

/*
 * Figure out who a message is from.
 */
frombreak(buf, fbuf)
register char *buf, *fbuf;
{
	register char *p, *q;
	if (fbuf[0] && fromset) {	/* we already know who it's from */
		if (sender[0] == 0 || buf[4] == ':') {
#ifdef debug
			printf("sender set to: %s", buf);
#endif
			strcpy(sender, buf);
		}
		return;
	}
	/*
	 * Leave fancy Froms alone - this parsing is done by mail
	 * Just quote the double quotes to prevent interpetation 
	 * by the shell.
	 * rad@tek
	 */
	p = any(buf, " \t");
	if (p==NULL)
		p = buf + 4;
	q = fbuf;
	while (*++p) {
		if (*p == '"')
			*q++ = '\\';
		*q++ = *p;
	}
	q[-1] = '\0';
	if ((p=index(fbuf,'\n')) != NULL)
		*p = '\0';
	if (buf[4] == ':')
		fromset++;
}

/*
 * Return the ptr in sp at which a character in sq appears;
 * NULL if not found
 *
 */
char *
any(sp, sq)
char *sp, *sq;
{
	register c1, c2;
	register char *q;

	while (c1 = *sp++) {
		q = sq;
		while (c2 = *q++)
			if (c1 == c2)
				return(--sp);
	}
	return(NULL);
}

/*
 *	This is similar to open, but made more secure.  Rather than
 *	forking off a shell, you get a bare process.
 *	You can use "" to get white space into an argument, but 
 *	nothing else is recognized
 */

#define	RDR	0
#define	WTR	1
#define MAXARGS	20
static	int	mopen_pid[20];

FILE *
pipeopen(cmd)
register char *cmd;
{
	int p[2];
	register myside, hisside, pid;

	if(pipe(p) < 0)
		return NULL;
	myside = p[WTR];
	hisside = p[RDR];
	if ((pid = vfork()) == 0) {
		char *args[MAXARGS];
		register char **ap = args;

		/* myside and hisside reverse roles in child */
		(void) close(myside);
		(void) close(0);
		(void) dup(hisside);
		(void) close(hisside);
		(void) setgid(getgid());
		(void) setuid(getuid());

		while (isspace(*cmd))
			cmd++;

		while (*cmd != '\0') {
			*ap++ = cmd;
			if (ap >= &args[MAXARGS]) {
				fprintf(stderr, "Too many args to %s", args[0]);
				_exit(2);
			}
			while (*cmd && !isspace(*cmd)) {
				if (*cmd++ == '"') {
					register char *bcp = cmd-1;
					while (*cmd) {
						if(*cmd == '\\') {
							cmd++;
							*bcp++ = *cmd++;
						} else if (*cmd == '"')
							break;
						*bcp++ = *cmd++;
					}
					*bcp = '\0';
					cmd++;
				}
			}
			if (*cmd)
				*cmd++ = '\0';
			while (isspace(*cmd))
				cmd++;
		}
		*ap = (char *)NULL;

		execv(args[0], args);
		perror("pipeopen exec:");
		_exit(1);
	}

	if(pid == -1)
		return NULL;

	mopen_pid[myside] = pid;
	(void) close(hisside);
	return fdopen(myside, "w");
}

pipeclose(ptr)
FILE *ptr;
{
	register int f, r;
	SIGNAL_TYPE hstat, istat, qstat;
	int status;

	f = fileno(ptr);
	(void) fclose(ptr);
	istat = (int (*)())signal(SIGINT, SIG_IGN);
	qstat = (int (*)())signal(SIGQUIT, SIG_IGN);
	hstat = (int (*)())signal(SIGHUP, SIG_IGN);
	while((r = wait(&status)) != mopen_pid[f] && r != -1)
		;
	if(r == -1)
		status = -1;
	signal(SIGINT, istat);
	signal(SIGQUIT, qstat);
	signal(SIGHUP, hstat);
	return status;
}