Article View: de.comp.sources.os9
Article #14Tass for OS-9 Part02/03
From: Frank Kaefer
Date: Thu, 24 Dec 1992 13:05
Date: Thu, 24 Dec 1992 13:05
3489 lines
72853 bytes
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, ¬e_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, ¬e_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
Technical Details
Message-ID:
<1hccjaINN773@stasys.sta.sub.org>Path:
arc1-ca.pugleaf.net!sparky!uunet!elroy.jpl.nasa.gov!ames!sun-barr!news2me.EBay.Sun.COM!seven-up.East.Sun.COM!sungy!stasys!stasys!not-for-mailShow Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!sparky!uunet!elroy.jpl.nasa.gov!ames!sun-barr!news2me.EBay.Sun.COM!seven-up.East.Sun.COM!sungy!stasys!stasys!not-for-mail From: frank.kaefer@stasys.sta.sub.org (Frank Kaefer) Newsgroups: de.comp.sources.os9,comp.os.os9 Subject: Tass for OS-9 Part02/03 Message-ID: <1hccjaINN773@stasys.sta.sub.org> Date: 24 Dec 92 13:05:46 GMT Sender: news@stasys.sta.sub.org Followup-To: de.comp.sources.d Organization: Stasys News Server, Starnberg, Germany Lines: 3489 Approved: frank.kaefer@stasys.sta.sub.org (Frank Kaefer) NNTP-Posting-Host: stasys.sta.sub.org