🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: de.comp.sources.os9
1 messages
1 total messages Started by Frank Kaefer Thu, 24 Dec 1992 13:05
Tass for OS-9 Part02/03
#14
Author: Frank Kaefer
Date: Thu, 24 Dec 1992 13:05
3489 lines
72853 bytes
Submitted-by: Ulrich Dessauer <ud@Nightmare.ddt.sub.org>
Archive-name: tass/part02

: ----- Cut here ----- Cut here ----- Cut here ----- Cut here -----
: Use  sh filename  to extract shell archive
: This shell archive contains following files:
:     'mail.c                                        836 bytes'
:     'main.c                                      23086 bytes'
:     'misc.c                                       8468 bytes'
:     'page.c                                      31558 bytes'
: 
if test -f 'mail.c' ; then
  echo 'File mail.c already exists, overwriting it'
  del 'mail.c'
fi
echo Extracting \"'mail.c'\"
sed "s/^X//" >'mail.c' <<'__END__OF__THIS__FILE__'
X
X#include	<stdio.h>
X#ifndef		OSK
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#else		/* OSK */
X#include	<types.h>
X#include	<stat.h>
Xtypedef long	off_t;
X#endif		/* OSK */
X#include	"tass.h"
X
Xchar *mailbox_name = NULL;
Xoff_t mailbox_size;
X
X
X/*
X *  Record size of mailbox so we can detect if new mail has arrived
X */
X
Xmail_setup() {
X	struct stat buf;
X	extern char *getenv();
X
X	if (do_mail_check) {
X		if (mailbox_name == NULL)
X			mailbox_name = getenv("MAIL");
X
X		if (mailbox_name == NULL)
X			mailbox_size = 0;
X		else {
X			if (stat(mailbox_name, &buf) >= 0)
X				mailbox_size = buf.st_size;
X			else
X				mailbox_size = 0;
X		}
X	}
X}
X
X
X/*
X *  Return TRUE if new mail has arrived
X */
X
Xmail_check() {
X	struct stat buf;
X
X	if (mailbox_name != NULL
X	&&  stat(mailbox_name, &buf) >= 0
X	&&  mailbox_size < buf.st_size)
X		return TRUE;
X
X	return FALSE;
X}
X
__END__OF__THIS__FILE__
if test -f 'main.c' ; then
  echo 'File main.c already exists, overwriting it'
  del 'main.c'
fi
echo Extracting \"'main.c'\"
sed "s/^X//" >'main.c' <<'__END__OF__THIS__FILE__'
X
X/*
X *  Tass, a visual Usenet news reader
X *  (c) Copyright 1990 by Rich Skrenta
X *
X *  Distribution agreement:
X *
X *	You may freely copy or redistribute this software, so long
X *	as there is no profit made from its use, sale, trade or
X *	reproduction.  You may not change this copyright notice,
X *	and it must be included prominently in any copy made.
X */
X
X#include	<stdio.h>
X#include	<signal.h>
X#ifdef	OSK
X#include	<modes.h>
X#include	<pwd.h>
X#else	/* OSK */
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#endif	/* OSK */
X#include	"tass.h"
X
X#ifdef	OSK
Xextern char	*index ();
X
Xextern
X#endif	/* OSK */
Xint LINES, COLS;
X
Xint max_active;
Xstruct group_ent *active;		/* active file */
Xint group_hash[TABLE_SIZE];		/* group name --> active[] */
Xint *my_group;				/* .newsrc --> active[] */
Xint *unread;				/* highest art read in group */
Xint num_active;				/* one past top of active */
Xint local_top;				/* one past top of my_group */
Xint update = FALSE;			/* update index files only mode */
X
Xstruct header *arts;
Xlong *base;
Xint max_art;
Xint top = 0;
Xint top_base;
X
X#ifdef	USE_UID
Xint tass_uid;
Xint tass_gid;
Xint real_uid;
Xint real_gid;
X#ifdef	OSK
X#define	DEF_TASSUID	(39 | (1 << 16))
X#endif	/* OSK */
X#endif	/* USE_UID */
X
Xint local_index;			/* do private indexing? */
X
Xint do_mail_check;			/* if we want to check for mail */
X
Xint omask;
X
Xjmp_buf jmp_buffer;
X
Xchar *cvers = "Tass 3.0  (c) Copyright 1991 by Rich Skrenta.  All rights reserved";
X
X
X#ifdef SIGTSTP
Xvoid
Xmain_susp(i)
Xint i;
X{
X
X	Raw(FALSE);
X	putchar('\n');
X	signal(SIGTSTP, SIG_DFL);
X	kill(0, SIGTSTP);
X
X	signal(SIGTSTP, main_susp);
X	mail_setup();
X	Raw(TRUE);
X}
X#endif
X
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	extern int optind, opterr;
X	extern char *optarg;
X	int errflag = 0;
X	int i;
X	int c;
X#ifdef	OSK
X	struct passwd	*pw;
X#endif	/* OSK */
X
X	for (i = 0; i < TABLE_SIZE; i++)
X		group_hash[i] = -1;
X
X#ifdef	SIGPIPE
X	signal(SIGPIPE, SIG_IGN);
X#endif	/* SIGPIPE */
X#ifdef SIGTSTP
X	signal(SIGTSTP, main_susp);
X#endif
X#ifdef	SIGQUIT
X	signal(SIGQUIT, SIG_IGN);
X#endif	/* SIGQUIT */
X#ifdef	SIGINT
X	signal(SIGINT, SIG_IGN);
X#endif	/* SIGINT */
X
X#ifdef	USE_UID
X#ifndef	OSK
X	tass_uid = geteuid();
X	tass_gid = getegid();
X	real_uid = getuid();
X	real_gid = getgid();
X#else	/* OSK */
X	real_uid = getuid ();
X	setpwent ();
X	if (pw = getpwnam ("news"))
X		tass_uid = pw->pw_uid | (pw->pw_gid << 16);
X	else
X		tass_uid = DEF_TASSUID;
X	endpwent ();
X	setup_convtable (TRUE, TRUE);
X	setuid (tass_uid);
X#endif	/* OSK */
X#endif	/* USE_UID */
X
X	omask = umask (0);
X	init_selfinfo();	/* set up char *'s: homedir, newsrc, etc. */
X	init_alloc();		/* allocate initial array sizes */
X
X#ifdef	USE_UID
X	if (tass_uid == real_uid) {	/* run out of someone's account */
X#endif	/* USE_UID */
X		local_index = FALSE;	/* index in their home directory */
X		if (access (indexdir, S_IFDIR) == -1)
X#ifndef	OSK
X			mkdir(indexdir, 0755);
X#else	/* OSK */
X			makdir (indexdir, S_IREAD | S_IWRITE, 033);
X#endif	/* OSK */
X#ifdef	USE_UID
X	} else			/* we're setuid, index in /usr/spool/news */
X		local_index = FALSE;
X#endif	/* USE_UID */
X
X	do_mail_check = FALSE;
X
X	read_active();		/* load the active file into active[] */
X
X	while ((c = getopt(argc, argv, "f:ugm")) != -1) {
X		switch(c) {
X		case 'f':
X			strcpy(newsrc, optarg);
X			break;
X
X		case 'u':
X			update = TRUE;
X			break;
X
X		case 'g':
X			local_index = TRUE;
X			break;
X
X		case 'm':
X			do_mail_check = TRUE;
X			break;
X
X		case '?':
X		default:
X			errflag++;
X		}
X	}
X
X	if (errflag) {
X	    fprintf(stderr, "usage: tass [options] [newsgroups]\n");
X	    fprintf(stderr, "   -f file   use file instead of $HOME/.newsrc\n");
X	    fprintf(stderr, "   -u        update index files only\n");
X	    fprintf(stderr, "   -g        don't use global instead of local index files\n");
X	    fprintf(stderr, "   -m        check for new mail while reading news\n");
X	    exit(1);
X	}
X
X	if (!update)
X		printf("Tass 3.0\n");
X
X	if (optind < argc) {
X		while (optind < argc) {
X			if (add_group(argv[optind], TRUE) < 0)
X				fprintf(stderr,
X					"group %s not found in active file\n",
X								argv[optind]);
X			optind++;
X		}
X	} else
X		read_newsrc(TRUE);
X
X	if (update) {			/* index file updater only */
X		do_update();
X		exit(0);
X	}
X
X	if (InitScreen() == FALSE) {
X		fprintf(stderr,"Screen initialization failed\n");
X		exit(1);
X	}
X
X	if (!setjmp (jmp_buffer)) {
X		ScreenSize(&LINES, &COLS);
X		Raw(TRUE);
X
X		mail_setup();		/* record mailbox size for "you have mail" */
X		selection_index();
X	}
X
X	tass_done(0);
X}
X
X
X
Xtass_done(ret)
Xint ret;
X{
X
X	MoveCursor(LINES, 0);
X	printf("\r\012");
X	Raw(FALSE);
X	umask (omask);
X	exit(ret);
X}
X
X
X/*
X *  Dynamic table management
X *  These settings are memory conservative:  small initial allocations
X *  and a 50% expansion on table overflow.  A fast vm system with
X *  much memory might want to start with higher initial allocations
X *  and a 100% expansion on overflow, especially for the arts[] array.
X */
X
Xinit_alloc() {
X
X	max_active = 100;	/* initial alloc */
X
X	active = (struct group_ent *) my_malloc(sizeof(*active) * max_active);
X	my_group = (int *) my_malloc(sizeof(int) * max_active);
X	unread = (int *) my_malloc(sizeof(int) * max_active);
X
X	max_art = 300;		/* initial alloc */
X
X	arts = (struct header *) my_malloc(sizeof(*arts) * max_art);
X	base = (long *) my_malloc(sizeof(long) * max_art);
X}
X
X
Xexpand_art() {
X
X	max_art += max_art / 2;		/* increase by 50% */
X
X	arts = (struct header *) my_realloc(arts, sizeof(*arts) * max_art);
X	base = (long *) my_realloc(base, sizeof(long) * max_art);
X}
X
X
Xexpand_active() {
X
X	max_active += max_active / 2;		/* increase by 50% */
X
X	active = (struct group_ent *) my_realloc(active,
X						sizeof(*active) * max_active);
X	my_group = (int *) my_realloc(my_group, sizeof(int) * max_active);
X	unread = (int *) my_realloc(unread, sizeof(int) * max_active);
X}
X
X
X/*
X *  Load the active file into active[]
X */
X
Xread_active()
X{
X	FILE *fp;
X	char *p, *q;
X	char buf[200];
X	long h;
X	int i;
X
X	num_active = 0;
X
X	if ((fp = fopen(active_file, "r")) == NULL) {
X		fprintf(stderr, "can't open %s: ", active_file);
X		perror("");
X		exit(1);
X	}
X
X	while (fgets(buf, 200, fp) != NULL) {
X		for (p = buf; *p && *p != ' '; p++) ;
X		if (*p != ' ') {
X#ifndef	OSK
X			fprintf(stderr, "active file corrupt\n");
X#else	/* OSK */
X			fprintf(stderr, "active file corrupt in line '%s'\n", buf);
X#endif	/* OSK */
X			continue;
X		}
X
X		*p++ = '\0';
X
X		if (num_active >= max_active)
X			expand_active();
X
X		{		/* hash group name for fast lookup later */
X			char *t = buf;
X
X			h = *t++;
X			while (*t)
X				h = (h * 64 + *t++) % TABLE_SIZE;
X		}
X
X		if (group_hash[h] == -1)
X			group_hash[h] = num_active;
X		else {				/* hash linked list chaining */
X			for (i = group_hash[h]; active[i].next >= 0;
X						i = active[i].next) {
X				if (strcmp(active[i].name, buf) == 0)
X					goto read_active_continue;
X							/* kill dups */
X			}
X			if (strcmp(active[i].name, buf) == 0)
X				goto read_active_continue;
X			active[i].next = num_active;
X		}
X
X		for (q = p; *q && *q != ' '; q++) ;
X		if (*q != ' ') {
X			fprintf(stderr, "active file corrupt\n");
X			continue;
X		}
X
X		active[num_active].name = str_save(buf);
X
X		active[num_active].max = atol(p);
X		active[num_active].min = atol(q);
X
X		active[num_active].next = -1;	    /* hash chaining */
X		active[num_active].flag = NOTGOT;   /* not in my_group[] yet */
X
X		num_active++;
X
Xread_active_continue:;
X
X	}
X
X	fclose(fp);
X}
X
X
X
X/*
X *  Read $HOME/.newsrc into my_group[].  my_group[] ints point to
X *  active[] entries.  Sub_only determines whether we just read
X *  subscribed groups or all of them.
X */
Xvoid
Xread_newsrc(sub_only)
Xint sub_only;		/* TRUE=subscribed groups only, FALSE=all groups */
X{
X	FILE *fp;
X	char *p;
X	char buf[8192];
X	char c;
X	int i;
X
X	local_top = 0;
X
X#ifdef	USE_UID
X	setuid(real_uid);	/* become the user to write in his */
X	setgid(real_gid);	/* home directory */
X#endif	/* USE_UID */
X
X	fp = fopen(newsrc, "r");
X	if (fp == NULL) {		/* attempt to make a .newsrc */
X#ifdef	USE_UID
X		setuid(tass_uid);
X		setgid(tass_gid);
X#endif	/* USE_UID */
X		for (i = 0; i < num_active; i++) {
X			if (local_top >= max_active)
X				expand_active();
X			my_group[local_top] = i;
X			active[i].flag = 0;
X#if 0
X			unread[local_top] = active[i].max - active[i].min;
X#else
X			unread[local_top] = -1;
X#endif
X			local_top++;
X		}
X		write_newsrc();
X		return;
X	}
X
X	while (fgets(buf, 8192, fp) != NULL) {
X		p = buf;
X		while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
X			p++;
X		c = *p;
X		*p++ = '\0';
X		if (c == '!' && sub_only)
X			continue;		/* unsubscribed */
X
X		if ((i = add_group(buf, FALSE)) < 0) {
X		    fprintf(stderr, "group %s not found in active file\n", buf);
X		    continue;
X		}
X
X		if (c != '!')		/* if we're subscribed to it */
X			active[my_group[i]].flag |= SUBS;
X
X		unread[i] = parse_unread(p, my_group[i]);
X	}
X	fclose(fp);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X}
X
X
X/*
X *  Write a new newsrc from my_group[] and active[]
X *  Used to a create a new .newsrc if there isn't one already, or when
X *  the newsrc is reset.
X */
X
Xwrite_newsrc() {
X	FILE *fp;
X	int i;
X
X#ifdef	USE_UID
X	setuid(real_uid);	/* become the user to write in his */
X	setgid(real_gid);	/* home directory */
X#endif	/* USE_UID */
X
X	umask (omask);
X	fp = fopen(newsrc, "w");
X	if (fp == NULL)
X		goto write_newsrc_done;
X
X	for (i = 0; i < num_active; i++)
X		fprintf(fp, "%s: \n", active[i].name);
X
X	fclose(fp);
X
Xwrite_newsrc_done:
X	umask (0);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X}
X
X
X/*
X *  Load the sequencer rang lists and mark arts[] according to the
X *  .newsrc info for a particular group.  i.e.  rec.arts.comics: 1-94,97
X */
X
Xread_newsrc_line(group)
Xchar *group;
X{
X	FILE *fp;
X	char buf[8192];
X	char *p;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	fp = fopen(newsrc, "r");
X	if (fp == NULL)
X		goto read_newsrc_line_done;
X
X	while (fgets(buf, 8192, fp) != NULL) {
X		p = buf;
X		while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
X			p++;
X		*p++ = '\0';
X		if (strcmp(buf, group) != 0)
X			continue;
X		parse_seq(p);
X		break;
X	}
X
X	fclose(fp);
Xread_newsrc_line_done:
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#else	/* USE UID */
X	;
X#endif	/* USE_UID */
X}
X
X
X/*
X *  For our current group, update the sequencer information in .newsrc
X */
X
Xupdate_newsrc(group, groupnum)
Xchar *group;
Xint groupnum;			/* index into active[] for this group */
X{
X	FILE *fp;
X	FILE *newfp;
X	char buf[8192];
X	char *p;
X	char c;
X	int gotit = FALSE;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	umask (omask);
X	fp = fopen(newsrc, "r");
X	newfp = fopen(newnewsrc, "w");
X	if (newfp == NULL)
X		goto update_done;
X
X	if (fp != NULL) {
X		while (fgets(buf, 8192, fp) != NULL) {
X			for (p = buf; *p; p++)
X				if (*p == '\n') {
X					*p = '\0';
X					break;
X				}
X
X			p = buf;
X			while (*p && *p != ' ' && *p != ':' && *p != '!')
X					p++;
X			c = *p;
X			if (c != '\0')
X				*p++ = '\0';
X
X			if (c != '!')
X				c = ':';
X
X			if (strcmp(buf, group) == 0) {
X				fprintf(newfp, "%s%c ", buf, c);
X				gotit = TRUE;
X				print_seq(newfp, groupnum);
X				fprintf(newfp, "\n");
X			} else
X				fprintf(newfp, "%s%c%s\n", buf, c, p);
X		}
X		fclose(fp);
X	}
X
X	fclose(newfp);
X	unlink(newsrc);
X#ifndef	OSK
X	link(newnewsrc, newsrc);
X	unlink(newnewsrc);
X#else	/* OSK */
X	rename(newnewsrc, newsrc);
X#endif	/* OSK */
X
Xupdate_done:
X	umask (0);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X}
X
X
X/*
X *  Subscribe/unsubscribe to a group in .newsrc.  ch should either be
X *  '!' to unsubscribe or ':' to subscribe.  num is the group's index
X *  in active[].
X */
X
Xsubscribe(group, ch, num, out_seq)
Xchar *group;
Xchar ch;
Xint num;
Xint out_seq;				/* output sequencer info? */
X{
X	FILE *fp;
X	FILE *newfp;
X	char buf[8192];
X	char *p;
X	char c;
X	int gotit = FALSE;
X
X	if (ch == '!')
X		active[num].flag &= ~SUBS;
X	else
X		active[num].flag |= SUBS;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	umask (omask);
X	fp = fopen(newsrc, "r");
X	newfp = fopen(newnewsrc, "w");
X	if (newfp == NULL)
X		goto update_done;
X
X	if (fp != NULL) {
X		while (fgets(buf, 8192, fp) != NULL) {
X			for (p = buf; *p; p++)
X				if (*p == '\n') {
X					*p = '\0';
X					break;
X				}
X
X			p = buf;
X			while (*p && *p != ' ' && *p != ':' && *p != '!')
X					p++;
X			c = *p;
X			if (c != '\0')
X				*p++ = '\0';
X
X			if (c != '!')
X				c = ':';
X
X			if (strcmp(buf, group) == 0) {
X				fprintf(newfp, "%s%c%s\n", buf, ch, p);
X				gotit = TRUE;
X			} else
X				fprintf(newfp, "%s%c%s\n", buf, c, p);
X		}
X		fclose(fp);
X	}
X
X	if (!gotit) {
X		if (out_seq) {
X			fprintf(newfp, "%s%c ", group, ch);
X			print_seq(newfp, num);
X			fprintf(newfp, "\n");
X		} else
X			fprintf(newfp, "%s%c\n", group, ch);
X	}
X
X	fclose(newfp);
X	unlink(newsrc);
X#ifndef	OSK
X	link(newnewsrc, newsrc);
X	unlink(newnewsrc);
X#else	/* OSK */
X	rename(newnewsrc, newsrc);
X#endif	/* OSK */
X
Xupdate_done:
X	umask (0);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X}
X
Xvoid
Xprint_seq(fp, groupnum)
XFILE *fp;
Xint groupnum;			/* index into active[] for this group */
X{
X	int i;
X	int flag = FALSE;
X
X	if (top <= 0) {
X		if (active[groupnum].min > 1) {
X			fprintf(fp, "1-%ld", active[groupnum].min);
X			fflush(fp);
X		}
X		return;
X	}
X
X	i = 0;
X	if (arts[0].artnum > 1) {
X		for (; i < top && !arts[i].unread; i++) ;
X		if (i > 0)
X			fprintf(fp, "1-%ld", arts[i-1].artnum);
X		else
X			fprintf(fp, "1-%ld", arts[0].artnum - 1);
X		flag = TRUE;
X	}
X
X	for (; i < top; i++) {
X		if (!arts[i].unread) {
X			if (flag)
X				fprintf(fp, ",");
X			else
X				flag = TRUE;
X			fprintf(fp, "%ld", arts[i].artnum);
X			if (i+1 < top && !arts[i+1].unread) {
X				while (i+1 < top && !arts[i+1].unread)
X					i++;
X				fprintf(fp, "-%ld", arts[i].artnum);
X			}
X		}
X	}
X
X	if (!flag && active[groupnum].min > 1)
X		fprintf(fp, "1-%ld", active[groupnum].min);
X	fflush(fp);
X}
X
X
Xparse_seq(s)
Xchar *s;
X{
X	long low, high;
X	int i;
X
X	while (*s) {
X		while (*s && (*s < '0' || *s > '9'))
X			s++;
X
X		if (*s && *s >= '0' && *s <= '9') {
X			low = atol(s);
X			while (*s && *s >= '0' && *s <= '9')
X				s++;
X			if (*s == '-') {
X				s++;
X				high = atol(s);
X				while (*s && *s >= '0' && *s <= '9')
X					s++;
X			}  else
X				high = low;
X
X			for (i = 0; i < top; i++)
X				if (arts[i].artnum >= low &&
X				    arts[i].artnum <= high)
X					arts[i].unread = 0;
X		}
X	}
X}
X
X
Xparse_unread(s, groupnum)
Xchar *s;
Xint groupnum;			/* index for group in active[] */
X{
X	long low, high;
X	long last_high;
X	int i;
X	int sum = 0;
X	int gotone = FALSE;
X	int n;
X
X/*
X *  Read the first range from the .newsrc sequencer information.  If the
X *  top of the first range is higher than what the active file claims is
X *  the bottom, use it as the new bottom instead
X */
X
X	high = 0;
X	if (*s) {
X		while (*s && (*s < '0' || *s > '9'))
X			s++;
X
X		if (*s && *s >= '0' && *s <= '9') {
X			low = atol(s);
X			while (*s && *s >= '0' && *s <= '9')
X				s++;
X			if (*s == '-') {
X				s++;
X				high = atol(s);
X				while (*s && *s >= '0' && *s <= '9')
X					s++;
X			}  else
X				high = low;
X			gotone = TRUE;
X		}
X	}
X
X	if (high < active[groupnum].min)
X		high = active[groupnum].min;
X
X#ifdef	OSK
X	if (! gotone) {
X		high = active [groupnum].min;
X		low = high;
X		gotone = low != active[groupnum].max;
X	}
X#endif	/* OSK */
X
X	while (*s) {
X		last_high = high;
X
X		while (*s && (*s < '0' || *s > '9'))
X			s++;
X
X		if (*s && *s >= '0' && *s <= '9') {
X			low = atol(s);
X			while (*s && *s >= '0' && *s <= '9')
X				s++;
X			if (*s == '-') {
X				s++;
X				high = atol(s);
X				while (*s && *s >= '0' && *s <= '9')
X					s++;
X			}  else
X				high = low;
X
X			if (low > last_high)	/* otherwise seq out of order */
X				sum += (low - last_high) - 1;
X		}
X	}
X
X	if (gotone) {
X		if (active[groupnum].max > high)
X			sum += active[groupnum].max - high;
X		return sum;
X	}
X
X	n = (int) (active[groupnum].max - active[groupnum].min);
X	if (n < 2)
X		return 0;
X
X	return -1;
X}
X
X
Xget_line_unread(group, groupnum)
Xchar *group;
Xint groupnum;				/* index for group in active[] */
X{
X	FILE *fp;
X	char buf[8192];
X	char *p;
X	int ret = -1;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	fp = fopen(newsrc, "r");
X	if (fp == NULL) {
X#ifdef	USE_UID
X		setuid(tass_uid);
X		setgid(tass_gid);
X#endif	/* USE_UID */
X
X		return -1;
X	}
X
X	while (fgets(buf, 8192, fp) != NULL) {
X		p = buf;
X		while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
X			p++;
X		*p++ = '\0';
X		if (strcmp(buf, group) != 0)
X			continue;
X		ret = parse_unread(p, groupnum);
X		break;
X	}
X
X	fclose(fp);
X
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X
X	return ret;
X}
X
X
Xreset_newsrc()
X{
X	FILE *fp;
X	FILE *newfp;
X	char buf[8192];
X	char *p;
X	char c;
X	int gotit = FALSE;
X	int i;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	umask (omask);
X	fp = fopen(newsrc, "r");
X	newfp = fopen(newnewsrc, "w");
X	if (newfp == NULL)
X		goto update_done;
X
X	if (fp != NULL) {
X		while (fgets(buf, 8192, fp) != NULL) {
X			for (p = buf; *p && *p != '\n'; p++) ;
X			*p = '\0';
X
X			p = buf;
X			while (*p && *p != ' ' && *p != ':' && *p != '!')
X					p++;
X			c = *p;
X			if (c != '\0')
X				*p++ = '\0';
X
X			if (c != '!')
X				c = ':';
X
X			fprintf(newfp, "%s%c\n", buf, c);
X		}
X		fclose(fp);
X	}
X
X	fclose(newfp);
X	unlink(newsrc);
X#ifndef	OSK
X	link(newnewsrc, newsrc);
X	unlink(newnewsrc);
X#else	/* OSK */
X	rename(newnewsrc, newsrc);
X#endif	/* OSK */
X
Xupdate_done:
X	umask (0);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X
X	for (i = 0; i < local_top; i++)
X		unread[i] = -1;
X}
X
X
Xdelete_group(group)
Xchar *group;
X{
X	FILE *fp;
X	FILE *newfp;
X	char buf[8192];
X	char *p;
X	char c;
X	int gotit = FALSE;
X	FILE *del;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	umask (omask);
X	fp = fopen(newsrc, "r");
X	newfp = fopen(newnewsrc, "w");
X	if (newfp == NULL)
X		goto del_done;
X	del = fopen(delgroups, "a+");
X	if (del == NULL)
X		goto del_done;
X
X	if (fp != NULL) {
X		while (fgets(buf, 8192, fp) != NULL) {
X			for (p = buf; *p && *p != '\n'; p++) ;
X			*p = '\0';
X
X			p = buf;
X			while (*p && *p != ' ' && *p != ':' && *p != '!')
X					p++;
X			c = *p;
X			if (c != '\0')
X				*p++ = '\0';
X
X			if (c != '!')
X				c = ':';
X
X			if (strcmp(buf, group) == 0) {
X				fprintf(del, "%s%c%s\n", buf, c, p);
X				gotit = TRUE;
X			} else
X				fprintf(newfp, "%s%c%s\n", buf, c, p);
X		}
X		fclose(fp);
X	}
X
X	fclose(newfp);
X
X	if (!gotit)
X		fprintf(del, "%s! \n", group);
X
X	fclose(del);
X	unlink(newsrc);
X#ifndef	OSK
X	link(newnewsrc, newsrc);
X	unlink(newnewsrc);
X#else	/* OSK */
X	rename(newnewsrc, newsrc);
X#endif	/* OSK */
X
Xdel_done:
X	umask (0);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X}
X
X
Xundel_group() {
X	FILE *del;
X	FILE *newfp;
X	FILE *fp;
X	char buf[2][8192];
X	char *p;
X	int which = 0;
X	long h;
X	extern int cur_groupnum;
X	int i, j;
X	char c;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	del = fopen(delgroups, "r");
X	if (del == NULL) {
X#ifdef	USE_UID
X		setuid(tass_uid);
X		setgid(tass_gid);
X#endif	/* USE_UID */
X		return FALSE;
X	}
X	unlink(delgroups);
X	umask (omask);
X	newfp = fopen(delgroups, "w");
X	if (newfp == NULL) {
X		umask (0);
X#ifdef	USE_UID
X		setuid(tass_uid);
X		setgid(tass_gid);
X#endif	/* USE_UID */
X		return FALSE;
X	}
X
X	buf[0][0] = '\0';
X	buf[1][0] = '\0';
X
X	while (fgets(buf[which], 8192, del) != NULL) {
X		which = !which;
X		if (*buf[which])
X			fputs(buf[which], newfp);
X	}
X
X	fclose(del);
X	fclose(newfp);
X	which = !which;
X
X	if (!*buf[which]) {
X		umask (0);
X#ifdef	USE_UID
X		setuid(tass_uid);
X		setgid(tass_gid);
X#endif	/* USE_UID */
X		return FALSE;
X	}
X
X	for (p = buf[which]; *p && *p != '\n'; p++) ;
X	*p = '\0';
X
X	p = buf[which];
X	while (*p && *p != ' ' && *p != ':' && *p != '!')
X		p++;
X	c = *p;
X	if (c != '\0')
X		*p++ = '\0';
X
X	if (c != '!')
X		c = ':';
X
X	{			/* find the hash of the group name */
X		char *t = buf[which];
X
X		h = *t++;
X		while (*t)
X			h = (h * 64 + *t++) % TABLE_SIZE;
X	}
X
X	for (i = group_hash[h]; i >= 0; i = active[i].next) {
X		if (strcmp(buf[which], active[i].name) == 0) {
X			for (j = 0; j < local_top; j++)
X				if (my_group[j] == i) {
X					umask (0);
X#ifdef	USE_UID
X					setuid(tass_uid);
X					setgid(tass_gid);
X#endif	/* USE_UID */
X					return j;
X				}
X
X			active[i].flag &= ~NOTGOT;   /* mark that we got it */
X			if (c != '!')
X				active[i].flag |= SUBS;
X
X			if (local_top >= max_active)
X				expand_active();
X			local_top++;
X			for (j = local_top; j > cur_groupnum; j--) {
X				my_group[j] = my_group[j-1];
X				unread[j] = unread[j-1];
X			}
X			my_group[cur_groupnum] = i;
X			unread[cur_groupnum] = parse_unread(p, i);
X
X			fp = fopen(newsrc, "r");
X			if (fp == NULL) {
X				umask (0);
X#ifdef	USE_UID
X				setuid(tass_uid);
X				setgid(tass_gid);
X#endif	/* USE_UID */
X				return FALSE;
X			}
X			newfp = fopen(newnewsrc, "w");
X			if (newfp == NULL) {
X				fclose(fp);
X				umask (0);
X#ifdef	USE_UID
X				setuid(tass_uid);
X				setgid(tass_gid);
X#endif	/* USE_UID */
X				return FALSE;
X			}
X			i = 0;
X			while (fgets(buf[!which], 8192, fp) != NULL) {
X				for (p = buf[!which]; *p && *p != '\n'; p++) ;
X				*p = '\0';
X
X				p = buf[!which];
X				while (*p && *p!=' ' && *p != ':' && *p != '!')
X					p++;
X				c = *p;
X				if (c != '\0')
X					*p++ = '\0';
X
X				if (c != '!')
X					c = ':';
X
X				while (i < cur_groupnum) {
X					if (strcmp(buf[!which],
X					  active[my_group[i]].name) == 0) {
X						fprintf(newfp, "%s%c%s\n",
X							buf[!which], c, p);
X						goto foo_cont;
X					}
X					i++;
X				}
X				fprintf(newfp, "%s%c%s\n", buf[which], c, p);
X				fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
X				break;
Xfoo_cont:;
X			}
X
X			while (fgets(buf[!which], 8192, fp) != NULL)
X				fputs(buf[!which], newfp);
X
X			fclose(newfp);
X			fclose(fp);
X			unlink(newsrc);
X#ifndef	OSK
X			link(newnewsrc, newsrc);
X			unlink(newnewsrc);
X#else	/* OSK */
X			rename(newnewsrc, newsrc);
X#endif	/* OSK */
X			umask (0);
X#ifdef	USE_UID
X			setuid(tass_uid);
X			setgid(tass_gid);
X#endif	/* USE_UID */
X			return TRUE;
X		}
X	}
X
X	umask (0);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X
X	return FALSE;
X}
X
Xvoid
Xmark_group_read(group, groupnum)
Xchar *group;
Xint groupnum;			/* index into active[] for this group */
X{
X	FILE *fp;
X	FILE *newfp;
X	char buf[8192];
X	char *p;
X	char c;
X	int gotit = FALSE;
X
X	if (active[groupnum].max < 2)
X		return;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	umask (omask);
X	fp = fopen(newsrc, "r");
X	newfp = fopen(newnewsrc, "w");
X	if (newfp == NULL)
X		goto mark_group_read_done;
X
X	if (fp != NULL) {
X		while (fgets(buf, 8192, fp) != NULL) {
X			for (p = buf; *p; p++)
X				if (*p == '\n') {
X					*p = '\0';
X					break;
X				}
X
X			p = buf;
X			while (*p && *p != ' ' && *p != ':' && *p != '!')
X					p++;
X			c = *p;
X			if (c != '\0')
X				*p++ = '\0';
X
X			if (c != '!')
X				c = ':';
X
X			if (strcmp(buf, group) == 0) {
X				fprintf(newfp, "%s%c 1-%ld\n", buf, c,
X						active[groupnum].max);
X				gotit = TRUE;
X			} else
X				fprintf(newfp, "%s%c%s\n", buf, c, p);
X		}
X		fclose(fp);
X	}
X
X	fclose(newfp);
X	unlink(newsrc);
X#ifndef	OSK
X	link(newnewsrc, newsrc);
X	unlink(newnewsrc);
X#else	/* OSK */
X	rename(newnewsrc, newsrc);
X#endif	/* OSK */
X
Xmark_group_read_done:
X	umask (0);
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X}
__END__OF__THIS__FILE__
if test -f 'misc.c' ; then
  echo 'File misc.c already exists, overwriting it'
  del 'misc.c'
fi
echo Extracting \"'misc.c'\"
sed "s/^X//" >'misc.c' <<'__END__OF__THIS__FILE__'
X
X#include	<stdio.h>
X#include	<signal.h>
X#include	<pwd.h>
X#ifndef		OSK
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#else		/* OSK */
X#include	<types.h>
X#include	<stat.h>
X#endif		/* OSK */
X#include	"tass.h"
X
Xextern char *rindex ();
X
Xchar active_file[LEN];
X#ifdef	OSK
Xchar spooldir[LEN];
X#endif	/* OSK */
Xchar homedir[LEN];
Xchar userid[LEN];
Xchar delgroups[LEN];
Xchar newsrc[LEN];
Xchar newnewsrc[LEN];
Xchar indexdir[LEN];
Xchar my_org[LEN];		/* organization */
X#ifdef	INCSTR
Xchar *incstr;
X#endif	/* INCSTR */
X
X/*
X *  Which base note (an index into base[]) does a respnum
X *  (an index into arts[]) corresponsd to?
X *
X *  In other words, base[] points to an entry in arts[] which is
X *  the head of a thread, linked with arts[].thread.  For any q: arts[q],
X *  find i such that base[i]->arts[n]->arts[o]->...->arts[q]
X */
X
Xwhich_base(n)
Xint n;
X{
X	int i, j;
X
X	for (i = 0; i < top_base; i++)
X		for (j = base[i]; j >= 0; j = arts[j].thread)
X			if (j == n)
X				return i;
X
X	fprintf(stderr, "can't find base article\n");
X	return 0;
X}
X
X
X/*
X *  Find how deep in a thread a response is.  Start counting at zero
X */
X
Xwhich_resp(n)
Xint n;
X{
X	int i, j;
X	int num = 0;
X
X	i = which_base(n);
X
X	for (j = base[i]; j != -1; j = arts[j].thread)
X		if (j == n)
X			break;
X		else
X			num++;
X
X	return num;
X}
X
X
X/*
X *  Given an index into base[], find the number of responses for
X *  that basenote
X */
X
Xnresp(n)
Xint n;
X{
X	int i;
X	int oldi = -3;
X	int sum = 0;
X
X	assert(n < top_base);
X
X	for (i = base[n]; i != -1; i = arts[i].thread) {
X		assert(i != -2);
X		assert(i != oldi);
X		oldi = i;
X		sum++;
X	}
X
X	return sum - 1;
X}
X
X
Xasfail(file, line, cond)
Xchar	*file;
Xint	line;
Xchar	*cond;
X{
X	fprintf(stderr, "tass: assertion failure: %s (%d): %s\n",
X							file, line, cond);
X	exit(1);
X}
X
X
X/*
X *  Make regular expressions pleasant for the masses:  glob them
X */
X
Xglob_name(group, grp)
Xchar *group;
Xchar *grp;
X{
Xchar *p, *q;
X
X/*
X *  Prefix the .'s in the group name so they won't be interpreted
X *  as regular expression commands.  Change 'all' into '*'
X */
X
X	p = group;
X	q = grp;
X
X	if (strncmp(p, "all", 3) == 0 && (p[3] == '.' || p[3] == '\0')) {
X		*q++ = '.';
X		*q++ = '*';
X		p = &p[3];
X	}
X	while (*p != '\0') {
X		if (*p == '.') {
X			*q++ = '\\';
X			*q++ = '.';
X			p++;
X
X			if (strncmp(p, "all", 3) == 0 &&
X				(p[3] == '.' || p[3] == '\0')) {
X					*q++ = '.';
X					*q++ = '*';
X					p = &p[3];
X				}
X		} else if (*p == '*') {
X			*q++ = '.';
X			*q++ = '*';
X			p++;
X		} else
X			*q++ = *p++;
X	}
X	*q = '\0';
X}
X
X
X/*
X * init_selfinfo
X *   Deterimines users home directory, userid, and a path
X *   for an rc file in the home directory
X */
X
Xinit_selfinfo()
X{
X	struct passwd *myentry;
X	extern struct passwd *getpwuid();
X	struct stat sb;
X	char nam[LEN];
X	char *p;
X	extern char *getenv();
X	FILE *fp;
X
X#ifndef	OSK
X	myentry = getpwuid(getuid());
X#else	/* OSK */
X	setpwent ();
X#ifdef	USE_UID
X	myentry = getpwuid(real_uid () & 0xffff);
X#else	/* USE_UID */
X	myentry = getpwuid(getuid () & 0xffff);
X#endif	/* USE_UID */
X	endpwent ();
X#endif	/* OSK */
X	strcpy(userid, myentry->pw_name);
X	strcpy(homedir, myentry->pw_dir);
X
X	sprintf(newsrc, "%s/.newsrc", homedir);
X	sprintf(newnewsrc, "%s/.newnewsrc", homedir);
X	sprintf(delgroups, "%s/.delgroups", homedir);
X	sprintf(indexdir, "%s/.tindex", homedir);
X#ifndef	OSK
X	sprintf(active_file, "%s/active", LIBDIR);
X#else	/* OSK */
X	if (!info_str ("MNEWS.LIB", active_file, LEN - 20))
X		strcpy (active_file, LIBDIR);
X	strcat (active_file, "/Active");
X	if (!info_str ("MNEWS.DIR", spooldir, LEN))
X		strcpy (spooldir, SPOOLDIR);
X#endif	/* OSK */
X#ifdef	INCSTR
X	if (!(incstr = getenv ("INCSTR")))
X		incstr = "> ";
X#endif	/* INCSTR */
X
X	if (stat(active_file, &sb) >= 0)
X		goto got_active;
X
X#ifndef	OSK
X/*
X *  I hate forgetting to define LIBDIR correctly.  Guess a
X *  couple of likely places if it's not where LIBDIR says it is.
X */
X
X	strcpy(active_file, "/usr/lib/news/active");
X	if (stat(active_file, &sb) >= 0)
X		goto got_active;
X
X	strcpy(active_file, "/usr/local/lib/news/active");
X	if (stat(active_file, &sb) >= 0)
X		goto got_active;
X
X	strcpy(active_file, "/usr/public/lib/news/active");
X	if (stat(active_file, &sb) >= 0)
X		goto got_active;
X
X/*
X *  Oh well.  Revert to what LIBDIR says it is to produce a
X *  useful error message when read_active() fails later.
X */
X
X	sprintf(active_file, "%s/active", LIBDIR);
X#endif	/* OSK */
X
Xgot_active:
X
X	*my_org = '\0';
X	p = getenv("ORGANIZATION");
X	if (p != NULL) {
X		strcpy(my_org, p);
X		goto got_org;
X	}
X
X#ifndef	OSK
X	sprintf(nam, "%s/organization", LIBDIR);
X	fp = fopen(nam, "r");
X
X	if (fp == NULL) {
X		sprintf(nam, "/usr/lib/news/organization");
X		fp = fopen(nam, "r");
X	}
X
X	if (fp == NULL) {
X		sprintf(nam, "/usr/local/lib/news/organization");
X		fp = fopen(nam, "r");
X	}
X
X	if (fp == NULL) {
X		sprintf(nam, "/usr/public/lib/news/organization");
X		fp = fopen(nam, "r");
X	}
X
X	if (fp == NULL) {
X		sprintf(nam, "/etc/organization");
X		fp = fopen(nam, "r");
X	}
X
X	if (fp != NULL) {
X		if (fgets(my_org, LEN, fp) != NULL) {
X			for (p = my_org; *p && *p != '\n'; p++) ;
X			*p = '\0';
X		}
X		fclose(fp);
X	}
X#endif	/* OSK */
X
Xgot_org:;
X
X}
X
X
Xchar *
Xmy_malloc(size)
Xunsigned size;
X{
X	char *p;
X	extern char *malloc();
X
X	p = malloc(size);
X	if (p == NULL) {
X		fprintf(stderr, "tass: out of memory\n");
X		exit(1);
X	}
X	return p;
X}
X
X
Xchar *
Xmy_realloc(p, size)
Xchar *p;
Xunsigned size;
X{
X	extern char *malloc();
X	extern char *realloc();
X
X	if (p == NULL)
X		p = malloc(size);
X	else
X		p = realloc(p, size);
X
X	if (p == NULL) {
X		fprintf(stderr, "tass: out of memory\n");
X		exit(1);
X	}
X	return p;
X}
X
X
Xchar *
Xstr_save(s)
Xchar *s;
X{
Xchar *p;
X
X	assert(s != NULL);
X	
X	p = my_malloc(strlen(s) + 1);
X	strcpy(p, s);
X
X	return(p);
X}
X
X
Xcopy_fp(a, b, prefix)
XFILE *a;
XFILE *b;
Xchar *prefix;
X{
X	char buf[8192];
X
X	while (fgets(buf, 8192, a) != NULL) {
X#ifdef	MNEWS
X		conv_charset (buf, strlen (buf));
X#endif	/* MNEWS */
X		fprintf(b, "%s%s", prefix, buf);
X	}
X}
X
X
Xchar *
Xget_val(env, def)
Xchar *env;		/* Environment variable we're looking for	*/
Xchar *def;		/* Default value if no environ value found	*/
X{
X	extern char *getenv();
X	char *ptr;
X
X	if ((ptr = getenv(env)) != NULL)
X		return(ptr);
X	else
X		return(def);
X}
X
X
Xinvoke_editor(nam, line)
Xchar *nam;
Xint line;
X{
X	char buf[200];
X	static int first = TRUE;
X	static char editor[200];
X	static int type = -1;
X	char *ptr;
X
X	if (first) {
X#ifndef	OSK
X		strcpy(editor, get_val("EDITOR", "/usr/bin/vi"));
X#else	/* OSK */
X		strcpy(editor, get_val("EDITOR", "me"));
X#endif	/* OSK */
X		if (ptr = rindex (editor, '/'))
X			++ptr;
X		else
X			ptr = editor;
X		if (!strncmp (ptr, "vi", 2))
X			type = 0;
X		else if ((!strncmp (ptr, "me", 2)) || (!strncmp (ptr, "emacs")))
X			type = 1;
X		first = FALSE;
X	}
X
X	++line;
X	switch (type) {
X		case -1:
X		default:
X			sprintf(buf, "%s %s", editor, nam);
X			break;
X		case 0:
X			sprintf (buf, "%s +%d %s", editor, line, nam);
X			break;
X		case 1:
X			sprintf (buf, "%s -g=%d %s", editor, line, nam);
X			break;
X	}
X	printf("\r%s", buf);
X	CleartoEOLN ();
X	return invoke_cmd(buf);
X}
X
X
Xinvoke_cmd(nam)
Xchar *nam;
X{
X	int ret;
X#ifdef SIGTSTP
X	void (*susp)();
X#endif
X
X	Raw(FALSE);
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X#ifndef	OSK
X#ifdef SIGTSTP
X	susp = signal(SIGTSTP, SIG_DFL);
X#endif
X
X	ret = system(nam);
X
X#ifdef SIGTSTP
X	signal(SIGTSTP, susp);
X#endif
X#else	/* OSK */
X	ret = system (nam);
X#endif	/* OSK */
X
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X	Raw(TRUE);
X
X	return ret == 0;
X}
X
X
Xshell_escape() {
X	char shell[LEN];
X	char *p;
X#ifdef SIGTSTP
X	void (*susp)();
X#endif
X
X	if (!parse_string("!", shell))
X		strcpy(shell, get_val("SHELL", "/bin/sh"));
X
X	for (p = shell; *p && (*p == ' ' || *p == '\t'); p++) ;
X
X	if (!*p)
X		strcpy(shell, get_val("SHELL", "/bin/sh"));
X	
X	Raw(FALSE);
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	fputs("\r\012", stdout);
X
X#ifndef	OSK
X#ifdef SIGTSTP
X	susp = signal(SIGTSTP, SIG_DFL);
X#endif
X
X	system(p);
X
X#ifdef SIGTSTP
X	signal(SIGTSTP, susp);
X#endif
X#else	/* OSK */
X	system (p);
X#endif	/* OSK */
X
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X
X	Raw(TRUE);
X
X	continue_prompt();
X	mail_setup();
X}
X
X
X/*
X *  Find the next unread response in this group 
X */
X
Xnext_unread(n)
Xint n;
X{
X
X	while (n >= 0) {
X		if (arts[n].unread == 1)
X			return n;
X		n = next_response(n);
X	}
X
X	return -1;
X}
X
X
X/*
X *  Find the previous unread response in this thread
X */
X
Xprev_unread(n)
Xint n;
X{
X
X	while (n >= 0) {
X		if (arts[n].unread == 1)
X			return n;
X		n = prev_response(n);
X	}
X
X	return -1;
X}
X
__END__OF__THIS__FILE__
if test -f 'page.c' ; then
  echo 'File page.c already exists, overwriting it'
  del 'page.c'
fi
echo Extracting \"'page.c'\"
sed "s/^X//" >'page.c' <<'__END__OF__THIS__FILE__'
X
X#include	<stdio.h>
X#include	<signal.h>
X#ifndef	OSK
X#include	<sys/types.h>
X#include	<sys/stat.h>
X#else	/* OSK */
X#include	<types.h>
X#include	<stat.h>
X
Xextern FILE	*popen ();
X#endif	/* OSK */
X#include	"tass.h"
X
X#define		MAX_PAGES	1000
X#define		NOTE_UNAVAIL	-1
X
Xchar note_h_path[LEN];			/* Path:	*/
Xchar note_h_date[LEN];			/* Date:	*/
Xchar note_h_subj[LEN];			/* Subject:	*/
Xchar note_h_from[LEN];			/* From:	*/
Xchar note_h_reply[LEN];			/* Reply-To:	*/
Xchar note_h_org[LEN];			/* Organization: */
Xchar note_h_newsgroups[LEN];		/* Newsgroups:	*/
Xchar note_h_messageid[LEN];		/* Message-ID:	*/
Xchar note_h_distrib[LEN];		/* Distribution: */
Xchar note_h_followup[LEN];		/* Followup-To: */
X
Xint	note_line;
Xint	note_page;		/* what page we're on */
Xlong	note_mark[MAX_PAGES];	/* ftells on beginnings of pages */
XFILE	*note_fp;		/* the body of the current article */
Xint	note_end;		/* we're done showing this article */
Xint	rotate;			/* 0=normal, 13=rot13 decode */
X
Xstruct stat note_stat;		/* so we can tell how big it is */
X
Xchar	note_full_name[100];
Xchar	note_from_addr[100];
X
X
Xint last_resp;		/* current & previous article for - command */
Xint this_resp;
X
Xint glob_respnum;
Xchar *glob_page_group;
Xextern int cur_groupnum;
X
X
X#ifdef SIGTSTP
Xvoid
Xpage_susp(i)
Xint i;
X{
X
X	Raw(FALSE);
X	putchar('\n');
X	signal(SIGTSTP, SIG_DFL);
X	kill(0, SIGTSTP);
X
X	signal(SIGTSTP, page_susp);
X	mail_setup();
X	Raw(TRUE);
X	redraw_page(glob_respnum, glob_page_group);
X}
X#endif
X
X
Xshow_page(respnum, group, group_path)
Xint respnum;
Xchar *group;
Xchar *group_path;
X{
X	char ch;
X	int n;
X	long art;
X	int sav_unread;
X
Xrestart:
X
X	glob_respnum = respnum;
X	glob_page_group = group;
X
X#ifdef SIGTSTP
X	signal(SIGTSTP, page_susp);
X#endif
X
X	if (respnum != this_resp) {	   /* remember current & previous */
X		last_resp = this_resp;	   /* articles for - command */
X		this_resp = respnum;
X	}
X
X	rotate = 0;			/* normal mode, not rot13 */
X	art = arts[respnum].artnum;
X	sav_unread = arts[respnum].unread;
X	arts[respnum].unread = 0;	/* mark article as read */
X	open_note(art, group_path);
X
X	if (note_page == NOTE_UNAVAIL) {
X		ClearScreen();
X		printf("[Article %ld unvailable]\r\012", art);
X		fflush(stdout);
X	} else
X		show_note_page(respnum, group);
X
X	while (1) {
X		if ((n = ReadCh()) == EOF)
X			longjmp (jmp_buffer, 1);
X		ch = (char) n;
X
X		if ((ch >= '0' && ch <= '9') || (ch == '=')) {
X
X			if (ch != '=')
X				n = prompt_response(ch, respnum);
X			else {
X				n = choose_resp (which_base (respnum), 0);
X				info_message ("Base note selected");
X			}
X
X			if (n != -1) {
X				arts[respnum].unread = sav_unread;
X				respnum = n;
X				goto restart;
X			}
X
X		} else switch (ch) {
X			case '|':	/* pipe article into command */
X				pipe_article();
X				redraw_page(respnum, group);
X				break;
X
X			case 'I':	/* toggle inverse video */
X				inverse_okay = !inverse_okay;
X				if (inverse_okay)
X					info_message("Inverse video enabled");
X				else
X					info_message("Inverse video disabled");
X				goto pager_ctrlr;
X				break;
X
X			case 's':
X				save_art_to_file();
X				break;
X
X			case 'S':
X				save_thread_to_file(respnum, group_path);
X				break;
X
X			case ctrl('X'):
X			case '%':	/* toggle rot-13 mode */
X				if (rotate)
X					rotate = 0;
X				else
X					rotate = 13;
X				goto pager_ctrlr;
X				break;
X
X			case 'P':	/* previous unread article */
X				n = prev_unread(prev_response(respnum));
X				if (n == -1)
X				    info_message("No previous unread article");
X				else {
X					note_cleanup();
X					respnum = n;
X					goto restart;
X				}
X				break;
X
X			case 'F':	/* post a followup to this article */
X			case 'W':	/* ... compatible to notes */
X				if (post_response(group, TRUE)) {
X					update_newsrc(group,
X						my_group[cur_groupnum]);
X					n = which_base(respnum);
X					note_cleanup();
X					index_group(group, group_path);
X					read_newsrc_line(group);
X					respnum = choose_resp(n, nresp(n));
X					goto restart;
X				} else
X					redraw_page(respnum, group);
X				break;
X
X			case 'f':	/* post a followup to this article */
X			case 'w':	/* ... compatible to notes */
X				if (post_response(group, FALSE)) {
X					update_newsrc(group,
X						my_group[cur_groupnum]);
X					n = which_base(respnum);
X					note_cleanup();
X					index_group(group, group_path);
X					read_newsrc_line(group);
X					respnum = choose_resp(n, nresp(n));
X					goto restart;
X				} else
X					redraw_page(respnum, group);
X				break;
X
X			case 'z':	/* mark article as unread (to return) */
X				arts[respnum].unread = 2;
X				info_message("Article marked as unread");
X				break;
X
X			case 'K':	/* mark rest of thread as read */
X			case 'J':	/* ... compatible to notes */
X				for (n = respnum; n >= 0; n = arts[n].thread)
X					arts[n].unread = 0;
X				n = next_unread(next_response(respnum));
X				if (n == -1)
X					goto return_to_index;
X				else {
X					note_cleanup();
X					respnum = n;
X					goto restart;
X				}
X				break;
X
X			case 'i':	/* return to index page */
X			case ctrl('B'):	/* possibly cursor doen */
Xreturn_to_index:
X				note_cleanup();
X				return( which_base(respnum) );
X
X			case 't':	/* return to group selection page */
X				note_cleanup();
X				return -1;
X
X			case ctrl('R'):	  /* redraw beginning of article */
Xpager_ctrlr:
X				if (note_page == NOTE_UNAVAIL) {
X					ClearScreen();
X					printf("[Article %ld unvailable]\r\012",
X							arts[respnum].artnum);
X					fflush(stdout);
X				} else {
X					note_page = 0;
X					note_end = FALSE;
X					fseek(note_fp, note_mark[0], 0);
X					show_note_page(respnum, group);
X				}
X				break;
X
X			case '!':
X				shell_escape();
X				redraw_page(respnum, group);
X				break;
X
X			case '\b':
X			case 'b':	/* back a page */
X			case ctrl('P'):	/* possibly cursor doen */
X				if (note_page == NOTE_UNAVAIL
X				||  note_page <= 1) {
X					note_cleanup();
X					n = prev_response(respnum);
X					if (n == -1)
X						return( which_resp(respnum) );
X
X					respnum = n;
X					goto restart;
X
X				} else {
X					note_page -= 2;
X					note_end = FALSE;
X					fseek(note_fp, note_mark[note_page], 0);
X					show_note_page(respnum, group);
X				}
X				break;
X
X			case 'm':	/* mail article to somebody */
X				mail_to_someone();
X				redraw_page(respnum, group);
X				break;
X
X			case 'r':	/* reply to author through mail */
X				mail_to_author(FALSE);
X				redraw_page(respnum, group);
X				break;
X
X			case 'R':	/* reply to author, copy text */
X				mail_to_author(TRUE);
X				redraw_page(respnum, group);
X				break;
X
X			case '-':	/* show last viewed article */
X				if (last_resp < 0) {
X					info_message("No last message");
X					break;
X				}
X				note_cleanup();
X				respnum = last_resp;
X				goto restart;
X
X
X			case 'p':	/* previous article */
X				note_cleanup();
X				n = prev_response(respnum);
X				if (n == -1)
X					return( which_resp(respnum) );
X
X				respnum = n;
X				goto restart;
X
X			case 'n':	/* skip to next article */
X				note_cleanup();
X				n = next_response(respnum);
X				if (n == -1)
X					return( which_base(respnum) );
X
X				respnum = n;
X				goto restart;
X
X			case 'k':
X			case 'j':	/* ... compatible to notes */
X				if (note_page == NOTE_UNAVAIL) {
X					n = next_unread(next_response(respnum));
X					if (n == -1)
X						return( which_base(respnum) );
X
X					respnum = n;
X					goto restart;
X
X				} else {
X					note_cleanup();
X					n = next_unread(next_response(respnum));
X					if (n == -1)
X						return( which_base(respnum) );
X
X					respnum = n;
X					goto restart;
X				}
X				break;
X
X			case ' ': 	/* next page or response */
X			case ctrl('N'):	/* possibly cursor doen */
X				if (note_page == NOTE_UNAVAIL) {
X					n = next_response(respnum);
X					if (n == -1)
X						return( which_base(respnum) );
X
X					respnum = n;
X					goto restart;
X
X				} else if (note_end) {
X					note_cleanup();
X					n = next_response(respnum);
X					if (n == -1)
X						return( which_base(respnum) );
X
X					respnum = n;
X					goto restart;
X				} else
X					show_note_page(respnum, group);
X				break;
X
X			case '\t': 	/* next page or unread response */
X				if (note_page == NOTE_UNAVAIL) {
X					n = next_unread(next_response(respnum));
X					if (n == -1)
X						return( which_base(respnum) );
X
X					respnum = n;
X					goto restart;
X
X				} else if (note_end) {
X					note_cleanup();
X					n = next_unread(next_response(respnum));
X					if (n == -1)
X						return( which_base(respnum) );
X
X					respnum = n;
X					goto restart;
X				} else
X					show_note_page(respnum, group);
X				break;
X
X			case 'N':	/* next unread article */
X				n = next_unread(next_response(respnum));
X				if (n == -1)
X					info_message("No next unread article");
X				else {
X					note_cleanup();
X					respnum = n;
X					goto restart;
X				}
X				break;
X
X			case 'C':	/* Cancel */
X			case 'd':	/* delete */
X			case 'Z':	/* zap (director option in notes) */
X				note_cleanup();
X				cancel_article ();
X				note_page = NOTE_UNAVAIL;
X				/* Fall through ... */
X
X#ifndef	OSK
X			case '\r':
X#else	/* OSK */
X			case '\l':
X#endif	/* OSK */
X			case '\n':	/* go to start of next thread */
X			case ctrl('F'):	/* possibly cursor down */
X				note_cleanup();
X				n = next_basenote(respnum);
X				if (n == -1)
X					return( which_base(respnum) );
X
X				respnum = n;
X				goto restart;
X
X#ifndef	OSK
X			case 'q':	/* quit */
X				return -2;
X#endif	/* OSK */
X
X			case 'H':	/* show article headers */
X				if (note_page == NOTE_UNAVAIL) {
X					n = next_response(respnum);
X					if (n == -1)
X						return( which_base(respnum) );
X
X					respnum = n;
X					goto restart;
X				} else {
X					note_page = 0;
X					note_end = FALSE;
X					fseek(note_fp, 0L, 0);
X					show_note_page(respnum, group);
X				}
X				break;
X
X
X			case 'h':
X				tass_page_help();
X				redraw_page(respnum, group);
X				break;
X
X			default:
X			    info_message("Bad command.  Type 'h' for help.");
X		}
X	}
X}
X
X
Xnote_cleanup() {
X
X	if (note_page != NOTE_UNAVAIL)
X		fclose(note_fp);
X}
X
X
Xredraw_page(respnum, group)
Xint respnum;
Xchar *group;
X{
X
X	if (note_page == NOTE_UNAVAIL) {
X		ClearScreen();
X		printf("[Article %ld unvailable]\r\012", arts[respnum].artnum);
X		fflush(stdout);
X	} else if (note_page > 0) {
X		note_page--;
X		fseek(note_fp, note_mark[note_page], 0);
X		show_note_page(respnum, group);
X	}
X}
X
X
Xshow_note_page(respnum, group)
Xint respnum;
Xchar *group;
X{
X	char buf[LEN];
X	char buf2[LEN+50];
X	int percent;
X	char *p, *q;
X	int i, j;
X	int ctrl_L;		/* form feed character detected */
X
X	ClearScreen();
X
X	note_line = 1;
X
X	if (note_page == 0)
X		show_first_header(respnum, group);
X	else
X		show_cont_header(respnum);
X
X	ctrl_L = FALSE;
X	while (note_line < LINES) {
X		if (fgets(buf, LEN, note_fp) == NULL) {
X			note_end = TRUE;
X			break;
X		}
X
X		buf[LEN-1] = '\0';
X#ifdef	MNEWS
X		conv_charset (buf, strlen (buf));
X#endif	/* MNEWS */
X		if (rotate)
X			for (p = buf, q = buf2;
X					*p && *p != '\n' && q<&buf2[LEN]; p++) {
X				if (*p == '\b' && q > buf2) {
X					q--;
X				} else if (*p == 12) {		/* ^L */
X					*q++ = '^';
X					*q++ = 'L';
X					ctrl_L = TRUE;
X				} else if (*p == '\t') {
X					i = q - buf2;
X					j = (i|7) + 1;
X
X					while (i++ < j)
X						*q++ = ' ';
X				} else if (*p & 0x7F < 32) {
X					*q++ = '^';
X					*q++ = (*p & 0x7F) + '@';
X				} else if (*p >= 'A' && *p <= 'Z')
X					*q++ = 'A' + (*p - 'A' + rotate) % 26;
X				else if (*p >= 'a' && *p <= 'z')
X					*q++ = 'a' + (*p - 'a' + rotate) % 26;
X				else
X					*q++ = *p;
X			}
X		else
X			for (p = buf, q = buf2;
X					*p && *p != '\n' && q<&buf2[LEN]; p++) {
X				if (*p == '\b' && q > buf2) {
X					q--;
X				} else if (*p == 12) {		/* ^L */
X					*q++ = '^';
X					*q++ = 'L';
X					ctrl_L = TRUE;
X				} else if (*p == '\t') {
X					i = q - buf2;
X					j = (i|7) + 1;
X
X					while (i++ < j)
X						*q++ = ' ';
X				} else if ((*p & 0x7F) < 32) {
X					*q++ = '^';
X					*q++ = (*p & 0x7F) + '@';
X				} else
X					*q++ = *p;
X			}
X
X		*q = '\0';
X
X		printf("%s\r\012", buf2);
X
X#if 1
X		note_line += (strlen(buf2) / COLS) + 1;
X#else
X		if (*buf2)
X			note_line += (strlen(buf2) + COLS) / (COLS+1);
X		else
X			note_line++;
X#endif
X		if (ctrl_L)
X			break;
X	}
X
X	note_mark[++note_page] = ftell(note_fp);
X
X	MoveCursor(LINES, MORE_POS);
X/*	StartInverse();	*/
X	if (note_end) {
X		if (arts[respnum].thread != -1)
X			printf("-- next response --");
X		else
X			printf("-- last response --");
X	} else {
X		if (note_stat.st_size > 0) {
X		    percent = note_mark[note_page] * 100 / note_stat.st_size;
X		    printf("--More--(%d%%)", percent);
X		} else
X		    printf("--More--");
X	}
X/*	EndInverse();	*/
X
X	fflush(stdout);
X}
X
X
Xshow_first_header(respnum, group)
Xint respnum;
Xchar *group;
X{
X	int whichresp;
X	int x_resp;
X	char buf[200];
X	char tmp[200];
X	int pos, i;
X	int n;
X
X	whichresp = which_resp( respnum );
X	x_resp = nresp( which_base(respnum) );
X
X	ClearScreen();
X
X	strcpy(buf, note_h_date);
X	pos = (COLS - strlen(group)) / 2;
X	for (i = strlen(buf); i < pos; i++)
X		buf[i] = ' ';
X	buf[i] = '\0';
X
X	strcat(buf, group);
X
X	for (i = strlen(buf); i < RIGHT_POS; i++)
X		buf[i] = ' ';
X	buf[i] = '\0';
X
X	printf("%sNote %3d of %3d\r\012", buf, which_base(respnum) + 1, top_base);
X
X	sprintf(buf, "Article %ld  ", arts[respnum].artnum);
X	n = strlen(buf);
X	fputs(buf, stdout);
X
X	pos = (COLS - strlen( note_h_subj )) / 2 - 2;
X
X	if (pos > n)
X		MoveCursor(1, pos);
X	else
X		MoveCursor(1, n);
X
X	StartInverse();
X	strcpy(buf, note_h_subj);
X	buf[RIGHT_POS - 2 - n] = '\0';
X	fputs(buf, stdout);
X	EndInverse();
X
X	MoveCursor(1, RIGHT_POS);
X	if (whichresp)
X		printf("Resp %3d of %3d\r\012", whichresp, x_resp);
X	else {
X		if (x_resp == 0)
X			printf("No responses\r\012");
X		else if (x_resp == 1)
X			printf("1 Response\r\012");
X		else
X			printf("%d Responses\r\012", x_resp);
X	}
X
X	if (*note_h_org)
X		sprintf(tmp, "%s at %s", note_full_name, note_h_org);
X	else
X		strcpy(tmp, note_full_name);
X
X	tmp[79] = '\0';
X
X	sprintf(buf, "%s  ", note_from_addr);
X
X	pos = COLS - 1 - strlen(tmp);
X	if (strlen(buf) + strlen(tmp) >= COLS - 1) {
X		strncat(buf, tmp, COLS - 1 - strlen(buf));
X		buf[COLS - 1] = '\0';
X	} else {
X		for (i = strlen(buf); i < pos; i++)
X			buf[i] = ' ';
X		buf[i] = '\0';
X		strcat(buf, tmp);
X	}
X	printf("%s\r\012\r\012", buf);
X
X	note_line += 4;
X}
X
X
Xshow_cont_header(respnum)
Xint respnum;
X{
Xint whichresp;
Xint whichbase;
Xchar buf[LEN+60];
X
X	whichresp = which_resp(respnum);
X	whichbase = which_base(respnum);
X
X	assert (whichbase < top_base);
X
X	if (whichresp)
X		sprintf(buf, "Note %d of %d, Resp %d (page %d):  %s",
X			whichbase + 1,
X			top_base,
X			whichresp,
X			note_page + 1,
X			note_h_subj);
X	else
X		sprintf(buf, "Note %d of %d (page %d):  %s",
X			whichbase + 1,
X			top_base,
X			note_page + 1,
X			note_h_subj);
X
X	buf[COLS] = '\0';
X	printf("%s\r\012\r\012", buf);
X
X	note_line += 2;
X}
X
Xvoid
Xopen_note(art, group_path)
Xlong art;
Xchar *group_path;
X{
X	char buf[1025];
X
X	note_page = 0;
X
X#ifndef	OSK
X	sprintf(buf, "/usr/spool/news/%s/%ld", group_path, art);
X#else	/* OSK */
X	sprintf(buf, "%s/%s/%ld", spooldir, group_path, art);
X#endif	/* OSK */
X
X	if (stat(buf, &note_stat) < 0)
X		note_stat.st_size = 0;
X
X	note_fp = fopen(buf, "r");
X
X#ifdef	MNEWS
X	if (note_fp)
X		if (fgets (buf, 256, note_fp)) {
X			rewind (note_fp);
X			if (!strncmp (buf, "%(#)$ ", 6)) {
X				char	sav[200];
X
X				buf[strlen (buf) - 1] = '\0';
X				strcpy (sav, buf + 6);
X				sprintf (buf, "%s/%s", spooldir, sav);
X				fclose (note_fp);
X				if (stat (buf, &note_stat) < 0)
X					note_stat.st_size = 0;
X				note_fp = fopen (buf, "r");
X			}
X		}
X#endif	/* MNEWS */
X
X	if (note_fp == NULL) {
X		fprintf(stderr, "can't open %s: ", buf);
X		perror("");
X		note_page = NOTE_UNAVAIL;
X		return;
X	}
X
X	note_h_from[0] = '\0';
X	note_h_reply[0] = '\0';
X	note_h_path[0] = '\0';
X	note_h_subj[0] = '\0';
X	note_h_org[0] = '\0';
X	note_h_date[0] = '\0';
X	note_h_newsgroups[0] = '\0';
X	note_h_messageid[0] = '\0';
X	note_h_distrib[0] = '\0';
X	note_h_followup[0] = '\0';
X
X	while (fgets(buf, 1024, note_fp) != NULL) {
X		buf[1024] = '\0';
X		buf[strlen(buf)-1] = '\0';
X#ifdef	MNEWS
X		conv_charset (buf, strlen (buf));
X#endif	/* MNEWS */
X
X		if (*buf == '\0')
X			break;
X
X		if (strncmp(buf, "From: ", 6) == 0) {
X			strncpy(note_h_from, &buf[6], LEN);
X			note_h_from[LEN-1] = '\0';
X		} else if (strncmp(buf, "Reply-To: ", 10) == 0) {
X			strncpy(note_h_reply, &buf[10], LEN);
X			note_h_reply[LEN-1] = '\0';
X		} else if (strncmp(buf, "Path: ", 6) == 0) {
X			strncpy(note_h_path, &buf[6], LEN);
X			note_h_path[LEN-1] = '\0';
X		} else if (strncmp(buf, "Subject: ", 9) == 0) {
X			strncpy(note_h_subj, &buf[9], LEN);
X			note_h_subj[LEN-1] = '\0';
X		} else if (strncmp(buf, "Organization: ", 14) == 0) {
X			strncpy(note_h_org, &buf[14], LEN);
X			note_h_org[LEN-1] = '\0';
X		} else if (strncmp(buf, "Date: ", 6) == 0) {
X			strncpy(note_h_date, &buf[6], LEN);
X			note_h_date[LEN-1] = '\0';
X		} else if (strncmp(buf, "Newsgroups: ", 12) == 0) {
X			strncpy(note_h_newsgroups, &buf[12], LEN);
X			note_h_newsgroups[LEN-1] = '\0';
X		} else if (strncmp(buf, "Message-ID: ", 12) == 0) {
X			strncpy(note_h_messageid, &buf[12], LEN);
X			note_h_messageid[LEN-1] = '\0';
X		} else if (strncmp(buf, "Distribution: ", 14) == 0) {
X			strncpy(note_h_distrib, &buf[14], LEN);
X			note_h_distrib[LEN-1] = '\0';
X		} else if (strncmp(buf, "Followup-To: ", 13) == 0) {
X			strncpy(note_h_followup, &buf[13], LEN);
X			note_h_followup[LEN-1] = '\0';
X		}
X	}
X
X	note_page = 0;
X	note_mark[0] = ftell(note_fp);
X
X	parse_from(note_h_from, note_from_addr, note_full_name);
X	note_end = FALSE;
X
X	return;
X}
X
X
Xprompt_response(ch, respnum)
Xint respnum;
X{
X	int num;
X
X	clear_message();
X
X	if ((num = parse_num(ch, "Read response> ")) == -1) {
X		clear_message();
X		return(-1);
X	}
X
X	return choose_resp( which_base(respnum), num );
X}
X
X
X/*
X *  return response number n from thread i
X */
X
Xchoose_resp(i, n)
Xint i;
Xint n;
X{
X	int j;
X
X	j = base[i];
X
X	while (n-- && arts[j].thread >= 0)
X		j = arts[j].thread;
X
X	return j;
X}
X
X
X/*
X *  Parse various From: lines into the component mail addresses and
X *  real names
X */
X
Xparse_from(str, addr, name)
Xchar *str;
Xchar *addr;
Xchar *name;
X{
X	while (*str && *str != ' ')
X		*addr++ = *str++;
X	*addr = '\0';
X	if (*str++ == ' ') {
X		if (*str++ == '(') {
X			if (*str == '"')
X				str++;  /* Kill "quotes around names"         */
X					/* But don't touch quotes inside the  */
X					/* Name (that's what that nonsense    */
X					/* below is for			      */
X			while (*str && *str != ')' && !(*str=='"'&&str[1]==')'))
X				*name++ = *str++;
X		}
X	}
X	*name = '\0';
X}
X
X
X/*
X *  Find the previous response.  Go to the last response in the previous
X *  thread if we go past the beginning of this thread.
X */
X
Xprev_response(n)
Xint n;
X{
X	int resp;
X	int i;
X
X	resp = which_resp(n);
X
X	if (resp > 0)
X		return choose_resp( which_base(n), resp-1 );
X
X	i = which_base(n) - 1;
X
X	if (i < 0)
X		return -1;
X
X	return choose_resp( i, nresp(i) );
X}
X
X
X/*
X *  Find the next response.  Go to the next basenote if there
X *  are no more responses in this thread
X */
X
Xnext_response(n)
Xint n;
X{
X	int i;
X
X	if (arts[n].thread >= 0)
X		return arts[n].thread;
X
X	i = which_base(n) + 1;
X
X	if (i >= top_base)
X		return -1;
X
X	return base[i];
X}
X
X
X/*
X *  Given a respnum (index into arts[]), find the respnum of the
X *  next basenote
X */
X
Xnext_basenote(n)
Xint n;
X{
X	int i;
X
X	i = which_base(n) + 1;
X	if (i >= top_base)
X		return -1;
X
X	return base[i];
X}
X
Xvoid
Xtass_page_help() {
X	char ch;
X
Xpage_help_start:
X
X	ClearScreen();
X	center_line(0, TASS_HEADER);
X	center_line(1, "Article Pager Commands (page 1 of 2)");
X
X	MoveCursor(3, 0);
X
X	printf("0, =     Read the base article in this thread\r\012");
X	printf("4        Read response 4 in this thread\r\012");
X	printf("<CR>     Skip to next base article\r\012");
X	printf("<TAB>    Advance to next page or unread article\r\012");
X	printf("b        Back a page\r\012");
X	printf("f, w     Post a followup\r\012");
X	printf("F, W     Post a followup, copy text)\r\012");
X	printf("H        Show article headers\r\012");
X	printf("i        Return to index page\r\012");
X	printf("k, j      Mark article as read & advance to next unread\r\012");
X	printf("K, J      Mark rest of thread as read && advance to next unread\r\012");
X	printf("m        Mail this article to someone\r\012");
X	printf("n        Skip to the next article)\r\012");
X	printf("N        Skip to the next unread article\r\012");
X	printf("p        Go to the previous article\r\012");
X	printf("P        Go to the previous unread article\r\012");
X
X	center_line(LINES, "-- hit space for more commands --");
X	ch = ReadCh();
X	if (ch != ' ')
X		return;
X
X	ClearScreen();
X	center_line(0, TASS_HEADER);
X	center_line(1, "Article Pager Commands (page 2 of 2)");
X
X	MoveCursor(3, 0);
X
X	printf("q        Quit\r\012");
X	printf("r        Reply through mail to author\r\012");
X	printf("R        Reply through mail to author, copy text\r\012");
X	printf("s        Save article to file\r\012");
X	printf("S        Save thread to file\r\012");
X	printf("t        Return to group selection index\r\012");
X	printf("z        Mark article as unread\r\012");
X	printf("d, C, Z  delete article (if it's yours)\r\012");
X	printf("^R       Redisplay first page of article\r\012");
X	printf("%%, ^X    Toggle rot-13 decoding for this article\r\012");
X	printf("-        Show last message\r\012");
X	printf("|        Pipe article into command\r\012");
X
X	center_line(LINES, "-- hit any key --");
X	ch = ReadCh();
X
X	if (ch == 'b')
X		goto page_help_start;
X}
X
X
X
X/*
X *  Read a file grabbing the address given for To: and
X *  sticking it in mail_to
X */
Xvoid
Xfind_new_to(nam, mail_to)
Xchar *nam;
Xchar *mail_to;
X{
X	FILE *fp;
X	char buf[LEN];
X	char buf2[LEN];
X	char dummy[LEN];
X	char *ptr;
X
X	fp = fopen(nam, "r");
X	if (fp != NULL) {
X
X		while (fgets(buf, 1024, fp) != NULL) {
X			if (*buf == '\n')
X				break;
X			if (strncmp(buf, "To: ", 4) == 0) {
X				buf[strlen(buf)-1] = '\0';
X				strncpy(buf2, &buf[4], LEN);
X				buf2[LEN-1] = '\0';
X				parse_from(buf2, mail_to, dummy);
X				break;
X			}
X		}
X
X		fclose(fp);
X	}
X	for (ptr = mail_to; *ptr; ++ptr)
X		if (*ptr == ',')
X			*ptr++ = ' ';
X		else if (*ptr == '(') {
X			int	nest = 0;
X			while (*ptr) {
X				if (*ptr == '(')
X					++nest;
X				else if (*ptr == ')')
X					--nest;
X				*ptr++ = ' ';
X				if (nest <= 0)
X					break;
X			}
X		} else
X			++ptr;
X}
X
Xvoid
Xcancel_article () {
X	char	buf[LEN+40];
X	FILE	*pp;
X	int	err;
X
X	if (!note_h_messageid[0]) {
X		printf ("\rLost message-id!");
X		CleartoEOLN ();
X		return;
X	}
X	printf("\rCancel %s...  ", note_h_messageid);
X	CleartoEOLN ();
X#ifndef	MNEWS
X	Insert your cancel-cmd here!
X#else	/* MNEWS */
X	sprintf(buf, "inews '-c=cancel:%s'", note_h_messageid);
X#endif	/* MNEWS */
X	if (pp = popen (buf, "w")) {
X		fprintf (pp, "\nArticle canceled from tass\n");
X		err = pclose (pp);
X	} else
X		err = 1;
X	if (! err)
X		printf("article canceled ");
X	else
X		printf("article not canceled ");
X	continue_prompt();
X}
X
Xmail_to_someone() {
X	char nam[100];
X	FILE *fp;
X	char ch;
X	char buf[200];
X	char mail_to[LEN+1];
X	char subj[LEN+1];
X	int line;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	if (!parse_string("Mail article to: ", mail_to))
X		return(FALSE);
X	if (mail_to[0] == '\0')
X		return(FALSE);
X
X	sprintf(nam, "%s/.letter", homedir);
X	umask (omask);
X	if ((fp = fopen(nam, "w")) == NULL) {
X		umask (0);
X		fprintf(stderr, "can't open %s: ", nam);
X		perror("");
X		return(FALSE);
X	}
X#ifndef	OSK
X	chmod(nam, 0600);
X#else	/* OSK */
X	chmod(nam, 013);
X#endif	/* OSK */
X
X	fprintf(fp, "To: %s\n", mail_to);
X	fprintf(fp, "Subject: %s\n", note_h_subj);
X	if (*note_h_followup)
X		fprintf(fp, "Newsgroups: %s\n\n", note_h_followup);
X	else
X		fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
X	line = 3;
X	if (*my_org) {
X		fprintf(fp, "Organization: %s\n", my_org);
X		++line;
X	}
X	fputs("\n", fp);
X	++line;
X
X	fseek(note_fp, 0L, 0);
X	copy_fp(note_fp, fp, "");
X
X	fclose(fp);
X	umask (0);
X
X	while (1) {
X		do {
X			MoveCursor(LINES, 0);
X			fputs("abort, edit, send: ", stdout);
X			fflush(stdout);
X			ch = ReadCh();
X		} while (ch != 'a' && ch != 'e' && ch != 's');
X
X		switch (ch) {
X		case 'e':
X			invoke_editor(nam, line);
X			break;
X
X		case 'a':
X			return FALSE;
X
X		case 's':
X/*
X *  Open letter an get the To: line in case they changed it with
X *  the editor
X */
X
X			find_new_to(nam, mail_to);
X			printf("\rMailing to %s...", mail_to);
X			CleartoEOLN ();
X#ifndef	OSK
X			sprintf(buf, "%s \"%s\" < %s", MAILER,
X#else	/* OSK */
X			sprintf(buf, "%s \"%s\" <%s", MAILER,
X#endif	/* OSK */
X							mail_to, nam);
X			if (invoke_cmd(buf)) {
X				printf("Message sent ");
X				fflush(stdout);
X				goto mail_to_someone_done;
X			} else {
X				printf("Command failed: %s ", buf);
X				fflush(stdout);
X				break;
X			}
X		}
X	}
X
Xmail_to_someone_done:
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X
X	continue_prompt();
X
X	return TRUE;
X}
X
Xmail_to_author(copy_text)
Xint copy_text;
X{
X	char nam[100];
X	FILE *fp;
X	char ch;
X	char buf[200];
X	char mail_to[LEN+1];
X	int line;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	printf("\r\012Mailing to %s...\r\012\r\012", note_h_from);
X
X	sprintf(nam, "%s/.letter", homedir);
X	umask (omask);
X	if ((fp = fopen(nam, "w")) == NULL) {
X		umask (0);
X		fprintf(stderr, "can't open %s: ", nam);
X		perror("");
X		return(FALSE);
X	}
X#ifndef	OSK
X	chmod(nam, 0600);
X#else	/* OSK */
X	chmod(nam, 013);
X#endif	/* OSK */
X
X	fprintf(fp, "To: %s\n", note_h_from);
X	fprintf(fp, "Subject: Re: %s\n", eat_re(note_h_subj) );
X	fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
X	line = 3;
X	if (*my_org) {
X		fprintf(fp, "Organization: %s\n", my_org);
X		++line;
X	}
X	fputs("\n", fp);
X	++line;
X
X	if (copy_text) {		/* if "copy_text" */
X		fprintf(fp, "In article %s you write:\n", note_h_messageid);
X
X		fseek(note_fp, note_mark[0], 0);
X#ifndef	INCSTR
X		copy_fp(note_fp, fp, "> ");
X#else	/* INCSTR */
X		copy_fp(note_fp, fp, incstr);
X#endif	/* INCSTR */
X	}
X
X#ifdef	APPEND_SIG
X	add_signature (fp);
X#endif	/* APPEND_SIG */
X
X	fclose(fp);
X	umask (0);
X
X	ch = 'e';
X	while (1) {
X		switch (ch) {
X		case 'e':
X			invoke_editor(nam, line);
X			break;
X
X		case 'a':
X			return FALSE;
X
X		case 's':
X			strcpy(mail_to, note_h_reply[0] ? note_h_reply : note_from_addr);
X			find_new_to(nam, mail_to);
X			printf("\rMailing to %s...  ", mail_to);
X			CleartoEOLN ();
X#ifndef	OSK
X			sprintf(buf, "/usr/bin/rmail \"%s\" < %s",
X#else	/* OSK */
X			sprintf(buf, "%s \"%s\" <%s", MAILER,
X#endif	/* OSK */
X								mail_to, nam);
X			if (invoke_cmd(buf)) {
X				printf("Message sent ");
X				fflush(stdout);
X				goto mail_to_author_done;
X			} else {
X				printf("Command failed: %s ", buf);
X				fflush(stdout);
X				break;
X			}
X		}
X
X		do {
X			MoveCursor(LINES, 0);
X			fputs("abort, edit, send: ", stdout);
X			fflush(stdout);
X			ch = ReadCh();
X		} while (ch != 'a' && ch != 'e' && ch != 's');
X	}
X
Xmail_to_author_done:
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X
X	continue_prompt();
X
X	return TRUE;
X}
X
X
Xpost_response(group, respnum)
Xint respnum;
X{
X	FILE *fp;
X	char nam[100];
X	char ch;
X	char buf[200];
X	int post_anyway = FALSE;
X	int line;
X
X	if (*note_h_followup && strcmp(note_h_followup, "poster") == 0) {
X		clear_message();
X		MoveCursor(LINES,0);
X		printf("Note: Responses have been directed to the poster");
X		if (!prompt_yn("Post anyway? (y/n): "))
X			return FALSE;
X		*note_h_followup = '\0';
X	} else if (*note_h_followup && strcmp(note_h_followup, group) != 0) {
X	    clear_message();
X	    MoveCursor(LINES,0);
X	    printf("Note:  Responses have been directed to %s\r\012\r\012",
X							note_h_followup);
X	    if (!prompt_yn("Continue? (y/n): "))
X		return FALSE;
X	}
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	sprintf(nam, "%s/.article", homedir);
X	umask (omask);
X	if ((fp = fopen(nam, "w")) == NULL) {
X		umask (0);
X		fprintf(stderr, "can't open %s: ", nam);
X		perror("");
X		return FALSE;
X	}
X#ifndef	OSK
X	chmod(nam, 0600);
X#else	/* OSK */
X	chmod(nam, 013);
X#endif	/* OSK */
X
X	fprintf(fp, "Subject: Re: %s\n", eat_re(note_h_subj));
X
X	if (*note_h_followup && strcmp(note_h_followup, "poster") != 0)
X		fprintf(fp, "Newsgroups: %s\n", note_h_followup);
X	else
X		fprintf(fp, "Newsgroups: %s\n", note_h_newsgroups);
X	line = 2;
X
X	if (*my_org) {
X		fprintf(fp, "Organization: %s\n", my_org);
X		++line;
X	}
X
X	if (note_h_distrib != '\0') {
X		fprintf(fp, "Distribution: %s\n", note_h_distrib);
X		++line;
X	}
X
X	fprintf(fp, "References: %s\n", note_h_messageid);
X	fprintf(fp, "\n");
X	line += 2;
X
X	if (respnum) {		/* if "copy_text" */
X		fprintf(fp, "%s writes:\n", note_h_from);
X		++line;
X
X		fseek(note_fp, note_mark[0], 0);
X#ifndef	INCSTR
X		copy_fp(note_fp, fp, "> ");
X#else	/* INCSTR */
X		copy_fp(note_fp, fp, incstr);
X#endif	/* INCSTR */
X	}
X
X#ifdef	APPEND_SIG
X	add_signature (fp);
X#endif	/* APPEND_SIG */
X
X	fclose(fp);
X	umask (0);
X
X	ch = 'e';
X	while (1) {
X		switch (ch) {
X		case 'e':
X			invoke_editor(nam, line);
X			break;
X
X		case 'a':
X			return FALSE;
X
X		case 'p':
X			printf("\rPosting...  ");
X			CleartoEOLN ();
X#ifndef	OSK
X			sprintf(buf, "%s/inews -h < %s", LIBDIR, nam);
X#else	/* OSK */
X			sprintf(buf, "inews -h <%s", nam);
X#endif	/* OSK */
X			if (invoke_cmd(buf)) {
X				printf("article posted ");
X				fflush(stdout);
X				goto post_response_done;
X			} else {
X				printf("article rejected ");
X				fflush(stdout);
X				break;
X			}
X		}
X
X		do {
X			MoveCursor(LINES, 0);
X			fputs("abort, edit, post: ", stdout);
X			fflush(stdout);
X			ch = ReadCh();
X		} while (ch != 'a' && ch != 'e' && ch != 'p');
X	}
X
Xpost_response_done:
X#ifdef	USE_UID
X	setuid(tass_uid);
X	setgid(tass_gid);
X#endif	/* USE_UID */
X
X	continue_prompt();
X
X	return TRUE;
X}
X
Xvoid
Xsave_art_to_file()
X{
X	char nam[LEN];
X	FILE *fp;
X	char *p;
X
X	if (!parse_string("Save article to file: ", nam))
X		return;
X	if (nam[0] == '\0')
X		return;
X
X	for (p = nam; *p && (*p == ' ' || *p == '\t'); p++) ;
X	if (!*p)
X		return;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	umask (omask);
X	if ((fp = fopen(p, "a+")) == NULL) {
X		umask (0);
X		fprintf(stderr, "can't open %s: ", nam);
X		perror("");
X		info_message("-- article not saved --");
X#ifdef	USE_UID
X		setuid(real_uid);
X		setgid(real_gid);
X#endif	/* USE_UID */
X		return;
X	}
X
X	MoveCursor(LINES, 0);
X	fputs("Saving...", stdout);
X	fflush(stdout);
X
X	fprintf(fp, "From %s %s\n", note_h_path, note_h_date);
X
X	fseek(note_fp, 0L, 0);
X	copy_fp(note_fp, fp, "");
X	fputs("\n", fp);
X
X	fclose(fp);
X	umask (0);
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	info_message("-- article saved --");
X}
X
Xvoid
Xsave_thread_to_file(respnum, group_path)
Xlong respnum;
Xchar *group_path;
X{
X	char nam[LEN];
X	FILE *fp;
X	FILE *art;
X	int i;
X	char buf[8192];
X	int b;
X	int count = 0;
X	char *p;
X
X	b = which_base(respnum);
X
X	if (!parse_string("Save thread to file: ", nam))
X		return;
X	if (nam[0] == '\0')
X		return;
X
X	for (p = nam; *p && (*p == ' ' || *p == '\t'); p++) ;
X	if (!*p)
X		return;
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	umask (omask);
X	if ((fp = fopen(nam, "a+")) == NULL) {
X		umask (0);
X		fprintf(stderr, "can't open %s: ", nam);
X		perror("");
X		info_message("-- thread not saved --");
X#ifdef	USE_UID
X		setuid(real_uid);
X		setgid(real_gid);
X#endif	/* USE_UID */
X		return;
X	}
X
X	MoveCursor(LINES, 0);
X	fputs("Saving...    ", stdout);
X	fflush(stdout);
X
X	note_cleanup();
X
X	for (i = base[b]; i >= 0; i = arts[i].thread) {
X		open_note(arts[i].artnum, group_path);
X
X		fprintf(fp, "From %s %s\n", note_h_path, note_h_date);
X		fseek(note_fp, 0L, 0);
X		copy_fp(note_fp, fp, "");
X		fputs("\n", fp);
X
X		note_cleanup();
X		printf("\b\b\b\b%4d", ++count);
X		fflush(stdout);
X	}
X
X	fclose(fp);
X	umask (0);
X
X#ifdef	USE_UID
X	setuid(real_uid);
X	setgid(real_gid);
X#endif	/* USE_UID */
X
X	info_message("-- thread saved --");
X	open_note(arts[respnum].artnum, group_path);
X}
X
Xvoid
Xpipe_article() {
X	char command[LEN];
X	FILE *fp;
X
X	if (!parse_string("Pipe to command: ", command))
X		return;
X	if (command[0] == '\0')
X		return;
X
X	fp = popen(command, "w");
X	if (fp == NULL) {
X		fprintf(stderr, "command failed: ");
X		perror("");
X		goto pipe_article_done;
X	}
X
X	fseek(note_fp, 0L, 0);
X	copy_fp(note_fp, fp, "");
X	pclose(fp);
X
Xpipe_article_done:
X
X	continue_prompt();
X}
X
__END__OF__THIS__FILE__
exit 0
: end of shell archive

-- 
Frank Kaefer # fkk@stasys.sta.sub.org # Starnberg, Germany
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads