home *** CD-ROM | disk | FTP | other *** search
- Xref: sparky de.comp.sources.os9:14 comp.os.os9:1559
- Path: 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 Part01/03
- Message-ID: <1hccj4INN76t@stasys.sta.sub.org>
- Date: 24 Dec 92 13:05:40 GMT
- Sender: news@stasys.sta.sub.org
- Followup-To: de.comp.sources.d
- Organization: Stasys News Server, Starnberg, Germany
- Lines: 2372
- Approved: frank.kaefer@stasys.sta.sub.org (Frank Kaefer)
- NNTP-Posting-Host: stasys.sta.sub.org
-
- Submitted-by: Ulrich Dessauer <ud@Nightmare.ddt.sub.org>
- Archive-name: tass/part01
-
- : ----- Cut here ----- Cut here ----- Cut here ----- Cut here -----
- : Use sh filename to extract shell archive
- : This shell archive contains following files:
- : 'MANIFEST 660 bytes'
- : 'COPYRIGHT 356 bytes'
- : 'Makefile 679 bytes'
- : 'art.c 16520 bytes'
- : 'curses.c 8952 bytes'
- : 'group.c 16732 bytes'
- :
- if test -f 'MANIFEST' ; then
- echo 'File MANIFEST already exists, overwriting it'
- del 'MANIFEST'
- fi
- echo Extracting \"'MANIFEST'\"
- sed "s/^X//" >'MANIFEST' <<'__END__OF__THIS__FILE__'
- XFilename Part Description
- X----------------------------------------------------
- XMANIFEST 1 This shipping list
- XCOPYRIGHT 1
- XMakefile 1
- Xart.c 1
- Xcurses.c 1
- Xgroup.c 1
- Xmail.c 2
- Xmain.c 2
- Xmisc.c 2
- Xpage.c 2
- Xprompt.c 3
- Xscreen.c 3
- Xselect.c 3
- Xsigs.c 3
- Xtass.h 3
- Xtime.c 3
- __END__OF__THIS__FILE__
- if test -f 'COPYRIGHT' ; then
- echo 'File COPYRIGHT already exists, overwriting it'
- del 'COPYRIGHT'
- fi
- echo Extracting \"'COPYRIGHT'\"
- sed "s/^X//" >'COPYRIGHT' <<'__END__OF__THIS__FILE__'
- 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 */
- __END__OF__THIS__FILE__
- if test -f 'Makefile' ; then
- echo 'File Makefile already exists, overwriting it'
- del 'Makefile'
- fi
- echo Extracting \"'Makefile'\"
- sed "s/^X//" >'Makefile' <<'__END__OF__THIS__FILE__'
- XG= -g
- XCC= cc
- XCFLAGS= -qt=/dd/TMP $G -DREGEXP -DAPPEND_SIG -DMNEWS -DINCSTR \
- X -DLOCK_INDEX -DRAND_SIG
- XLIBS= -l=/dd/LIB/8bit.l -l=/dd/LIB/termlib.l -l=/dd/LIB/os9lib.l
- X
- X
- XOBJECTS = curses.r art.r group.r mail.r main.r misc.r page.r \
- X prompt.r screen.r select.r time.r sigs.r
- X
- X/h0/ETC/CMDS/tass: $(OBJECTS)
- X $(CC) $(CFLAGS) -m=20 -f=$@ $(OBJECTS) $(LIBS)
- X
- Xshar:
- X -mv -f ../tass.shar ../tass.shar-
- X shar -v [A-Z]* *.[ch] > ../tass.shar
- X
- X
- Xart.r: art.c tass.h
- Xcurses.r: curses.c
- Xgroup.r: group.c tass.h
- Xmail.r: mail.c
- Xmain.r: main.c tass.h
- Xmisc.r: misc.c tass.h
- Xpage.r: page.c tass.h
- Xprompt.r: prompt.c tass.h
- Xscreen.r: screen.c tass.h
- Xselect.r: select.c tass.h
- Xtime.r: time.c
- __END__OF__THIS__FILE__
- if test -f 'art.c' ; then
- echo 'File art.c already exists, overwriting it'
- del 'art.c'
- fi
- echo Extracting \"'art.c'\"
- sed "s/^X//" >'art.c' <<'__END__OF__THIS__FILE__'
- X
- X
- X#include <stdio.h>
- X#include <time.h>
- X#include <signal.h>
- X#include <errno.h>
- X#include "tass.h"
- X
- X
- X/* Hopefully one of these is right for you. */
- X
- X#ifdef BSD
- X# include <sys/types.h>
- X# include <sys/dir.h>
- X# define DIR_BUF struct direct
- X# define D_LENGTH d_namlen
- X#endif
- X#ifdef M_XENIX
- X# include <sys/ndir.h>
- X# define DIR_BUF struct direct
- X# define D_LENGTH d_namlen
- X#endif
- X#ifdef OSK
- X# include <ctype.h>
- X# include <modes.h>
- X# include <dir.h>
- X# define DIR_BUF struct direct
- X# define D_LENGTH d_namlen
- X# undef SPOOLDIR
- X# define SPOOLDIR spooldir
- X#endif /* OSK */
- X#ifndef DIR_BUF
- X# include <sys/types.h>
- X# include <dirent.h>
- X# define DIR_BUF struct dirent
- X# define D_LENGTH d_reclen
- X#endif
- X
- Xextern char *index ();
- Xextern char *realloc ();
- X
- Xchar index_file[LEN+1];
- Xchar *glob_art_group;
- X
- Xstatic int complete_count;
- Xstatic int complete_expire;
- X
- X#ifdef SIGTSTP
- Xvoid
- Xart_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, art_susp);
- X Raw(TRUE);
- X
- X mail_setup();
- X ClearScreen();
- X MoveCursor(LINES, 0);
- X printf("Group %s... ", glob_art_group);
- X fflush(stdout);
- X}
- X#endif
- X
- X
- X/*
- X * Convert a string to a long, only look at first n characters
- X */
- X
- Xmy_atol(s, n)
- Xchar *s;
- Xint n;
- X{
- X long ret = 0;
- X
- X while (*s && n--) {
- X if (*s >= '0' && *s <= '9')
- X ret = ret * 10 + (*s - '0');
- X else
- X return -1;
- X s++;
- X }
- X
- X return ret;
- X}
- X
- X# ifdef LOCK_INDEX
- X/*
- X * Lock the index when modifieng it (only on global indicies)
- X */
- Xstatic char *
- Xlock_filename (fle)
- Xchar *fle;
- X{
- X#ifndef OSK
- X static int siz = -1;
- X static char *fname = NULL;
- X int len;
- X
- X if ((len = strlen (fle)) > siz) {
- X siz = len;
- X if (! (fname = realloc (fname, siz + 16)))
- X return (NULL);
- X }
- X sprintf (fname, "%s_lock", fle);
- X return (fname);
- X#else
- X static char fname[64];
- X unsigned long n;
- X char *ptr;
- X
- X for (ptr = fle, n = 0; *ptr; n += *ptr++ & 0xff)
- X ;
- X sprintf (fname, "/dd/TMP/%u_lock", n);
- X return (fname);
- X#endif
- X}
- X
- X# ifdef OSK
- Xstatic void
- Xstop_signals ()
- X{
- X sigmask (1);
- X}
- X
- Xstatic void
- Xstart_signals ()
- X{
- X sigmask (-1);
- X}
- X# else /* OSK */
- Xtypedef int SIGTYPE;
- X
- Xstatic SIGTYPE (*signals)()[NSIG];
- X
- Xstatic void
- Xstop_signals ()
- X{
- X int t;
- X
- X for (t = 0; t < NSIG; ++t)
- X signals[t] = signal (t, SIG_IGN);
- X}
- X
- Xstatic void
- Xstart_signals ()
- X{
- X int t;
- X
- X for (t = 0; t < NSIG; ++t)
- X signal (t, signals[t]);
- X}
- X# endif /* OSK */
- X
- Xstatic int lock_fd = -1;
- X
- Xstatic int
- Xlock_index (fle)
- Xchar *fle;
- X{
- X int tout;
- X char *fn;
- X
- X if (lock_fd != -1)
- X close (lock_fd);
- X if (! (fn = lock_filename (fle)))
- X return (-1);
- X for (tout = 20; tout > 0; --tout) {
- X# ifndef OSK
- X if ((lock_fd = creat (fn, 0444)) == -1)
- X# else /* OSK */
- X unlink (fn);
- X if (((lock_fd = create (fn, S_IWRITE, 033)) == -1) && (errno == E_CEF))
- X# endif /* OSK */
- X sleep (1);
- X else
- X break;
- X }
- X if (lock_fd != -1)
- X stop_signals ();
- X return (lock_fd == -1 ? -1 : 0);
- X}
- X
- Xstatic void
- Xunlock_index (fle)
- Xchar *fle;
- X{
- X char *fn;
- X
- X if (lock_fd != -1) {
- X close (lock_fd);
- X lock_fd = -1;
- X if (fn = lock_filename (fle)) {
- X# ifndef OSK
- X chmod (fn, 0666);
- X# endif /* OSK */
- X unlink (fn);
- X }
- X start_signals ();
- X }
- X}
- X# endif /* LOCK_INDEX */
- X
- X/*
- X * Construct the pointers to the basenotes of each thread
- X * arts[] contains every article in the group. inthread is
- X * set on each article that is after the first article in the
- X * thread. Articles which have been expired have their thread
- X * set to -2.
- X */
- X
- Xfind_base() {
- X int i;
- X
- X top_base = 0;
- X
- X for (i = 0; i < top; i++)
- X if (!arts[i].inthread && arts[i].thread != -2) {
- X if (top_base >= max_art)
- X expand_art();
- X base[top_base++] = i;
- X }
- X}
- X
- X
- X/*
- X * Count the number of non-expired articles in arts[]
- X */
- X
- Xnum_arts() {
- X int sum = 0;
- X int i;
- X
- X for (i = 0; i < top; i++)
- X if (arts[i].thread != -2)
- X sum++;
- X
- X return sum;
- X}
- X
- X
- X/*
- X * Do we have an entry for article art?
- X */
- X
- Xvalid_artnum(art)
- Xlong art;
- X{
- X int i;
- X
- X for (i = 0; i < top; i++)
- X if (arts[i].artnum == art)
- X return i;
- X
- X return -1;
- X}
- X
- X
- X/*
- X * Return TRUE if arts[] contains any expired articles
- X * (articles we have an entry for which don't have a corresponding
- X * article file in the spool directory)
- X */
- X
- Xpurge_needed() {
- X int i;
- X
- X for (i = 0; i < top; i++)
- X if (arts[i].thread == -2)
- X return TRUE;
- X
- X return FALSE;
- X}
- X
- X
- X/*
- X * Main group indexing routine. Group should be the name of the
- X * newsgroup, i.e. "comp.unix.amiga". group_path should be the
- X * same but with the .'s turned into /'s: "comp/unix/amiga"
- X *
- X * Will read any existing index, create or incrementally update
- X * the index by looking at the articles in the spool directory,
- X * and attempt to write a new index if necessary.
- X */
- X
- Xindex_group(group, group_path)
- Xchar *group;
- Xchar *group_path;
- X{
- X int modified;
- X
- X glob_art_group = group;
- X
- X#ifdef SIGTSTP
- X signal(SIGTSTP, art_susp);
- X#endif
- X
- X if (!update) {
- X clear_message();
- X MoveCursor(LINES, 0);
- X printf("Group %s... ", group);
- X fflush(stdout);
- X }
- X
- X if (local_index)
- X find_local_index(group);
- X else
- X sprintf(index_file, "%s/%s/.tindex", SPOOLDIR, group_path);
- X
- X#ifdef LOCK_INDEX
- X if (! local_index)
- X if (lock_index (index_file) < 0)
- X return -1;
- X#endif /* LOCK_INDEX */
- X
- X load_index();
- X modified = read_group(group_path);
- X make_threads();
- X if (modified || purge_needed()) {
- X#ifdef USE_UID
- X if (local_index) { /* writing index in home directory */
- X setuid(real_uid); /* so become them */
- X setgid(real_gid);
- X }
- X#endif /* USE_UID */
- X dump_index(group);
- X#ifdef USE_UID
- X if (local_index) {
- X setuid(tass_uid);
- X setgid(tass_gid);
- X }
- X#endif /* USE_UID */
- X }
- X
- X#ifdef LOCK_INDEX
- X if (! local_index)
- X unlock_index (index_file);
- X#endif /* LOCK_INDEX */
- X
- X find_base();
- X
- X if (modified && !update)
- X clear_message();
- X}
- X
- X
- X/*
- X * Longword comparison routine for the qsort()
- X */
- X
- Xbase_comp(a, b)
- Xlong *a;
- Xlong *b;
- X{
- X
- X if (*a < *b)
- X return -1;
- X if (*a > *b)
- X return 1;
- X return 0;
- X}
- X
- X
- X/*
- X * Read the article numbers existing in a group's spool directory
- X * into base[] and sort them. base_top is one past top.
- X */
- X
- Xscan_dir(group)
- Xchar *group;
- X{
- X DIR *d;
- X DIR_BUF *e;
- X long art;
- X char buf[200];
- X
- X top_base = 0;
- X
- X sprintf(buf, "%s/%s", SPOOLDIR, group);
- X
- X d = opendir(buf);
- X if (d != NULL) {
- X while ((e = readdir(d)) != NULL) {
- X#ifdef OSK
- X e->D_LENGTH = strlen (e->d_name);
- X#endif /* OSK */
- X art = my_atol(e->d_name, e->D_LENGTH);
- X if (art >= 0) {
- X if (top_base >= max_art)
- X expand_art();
- X base[top_base++] = art;
- X }
- X }
- X closedir(d);
- X }
- X
- X qsort(base, top_base, sizeof(long), base_comp);
- X}
- X
- X
- X/*
- X * Index a group. Assumes any existing index has already been
- X * loaded.
- X */
- X
- Xread_group(group)
- Xchar *group;
- X{
- X char buf[200];
- X int fd;
- X long art;
- X int count;
- X int modified = FALSE;
- X int respnum;
- X int i;
- X
- X scan_dir(group); /* load article numbers into base[] */
- X
- X count = 0;
- X
- X for (i = 0; i < top_base; i++) { /* for each article # */
- X art = base[i];
- X
- X/*
- X * Do we already have this article in our index? Change thread from
- X * -2 to -1 if so and skip the header eating.
- X */
- X
- X if ((respnum = valid_artnum(art)) >= 0) {
- X arts[respnum].thread = -1;
- X arts[respnum].unread = 1;
- X continue;
- X }
- X
- X if (!modified) {
- X modified = TRUE; /* we've modified the index */
- X /* it will need to be re-written */
- X#if 0
- X if (!update) {
- X MoveCursor(LINES, 0);
- X fputs("Indexing... ", stdout);
- X fflush(stdout);
- X }
- X#endif
- X }
- X
- X/*
- X * Add article to arts[]
- X */
- X if (top >= max_art)
- X expand_art();
- X
- X arts[top].artnum = art;
- X arts[top].thread = -1;
- X arts[top].inthread = FALSE;
- X arts[top].unread = 1;
- X
- X sprintf(buf, "%s/%s/%ld", SPOOLDIR, group, art);
- X#ifndef MNEWS
- X fd = open(buf, 0);
- X#else /* MNEWS */
- X#ifndef OSK
- X if ((fd = open (buf, O_RDONLY)) != -1) {
- X#else /* OSK */
- X if ((fd = open (buf, S_IREAD)) != -1) {
- X#endif /* OSK */
- X int n;
- X n = readln (fd, buf, 180);
- X lseek (fd, 0, 0);
- X if (n > 0) {
- X buf[n - 1] = '\0';
- X if (!strncmp (buf, "%(#)$ ", 6)) {
- X char sav[200];
- X strcpy (sav, buf + 6);
- X sprintf (buf, "%s/%s", spooldir, sav);
- X close (fd);
- X#ifndef OSK
- X fd = open (buf, O_RDONLY);
- X#else /* OSK */
- X fd = open (buf, S_IREAD);
- X#endif /* OSK */
- X }
- X }
- X }
- X#endif /* MNEWS */
- X
- X if (fd < 0) {
- X fprintf(stderr, "can't open article %s: ", buf);
- X perror("");
- X continue;
- X }
- X
- X if (!parse_headers(fd, &arts[top]))
- X continue;
- X top++;
- X close(fd);
- X
- X if (++count % 10 == 0 && !update) {
- X printf("\b\b\b\b%4d", count);
- X fflush(stdout);
- X }
- X }
- X
- X complete_count += count;
- X
- X return modified;
- X}
- X
- X
- X/*
- X * Go through the articles in arts[] and use .thread to snake threads
- X * through them. Use the subject line to construct threads. The
- X * first article in a thread should have .inthread set to FALSE, the
- X * rest TRUE. Only do unexprired articles we haven't visited yet
- X * (arts[].thread == -1).
- X */
- X
- Xmake_threads() {
- X int i;
- X int j;
- X
- X for (i = 0; i < top; i++) {
- X if (arts[i].thread == -1)
- X for (j = i+1; j < top; j++)
- X if (arts[i].hash == arts[j].hash
- X && arts[j].thread != -2
- X && strncmp(arts[i].nore, arts[j].nore, 10) == 0) {
- X arts[i].thread = j;
- X arts[j].inthread = TRUE;
- X break;
- X }
- X }
- X}
- X
- X
- X/*
- X * Return a pointer into s eliminating any leading Re:'s. Example:
- X *
- X * Re: Reorganization of misc.jobs
- X * ^ ^
- X */
- X
- Xchar *
- Xeat_re(s)
- Xchar *s;
- X{
- X
- X#if 1
- X while (*s == 'r' || *s == 'R') {
- X if (*(s+1) == 'e' || *(s+1) == 'E') {
- X if (*(s+2) == ':')
- X s += 3;
- X else if ((*(s+2) == '^') && isdigit (*(s+3))) {
- X s += 4;
- X if (*s == ':')
- X ++s;
- X } else
- X break;
- X } else
- X break;
- X while (isspace (*s))
- X ++s;
- X }
- X#else
- X while (*s == 'R') {
- X if (strncmp(s, "Re: ", 4) == 0)
- X s += 4;
- X else if (strncmp(s, "Re:", 3) == 0)
- X s += 3;
- X else if (strncmp(s, "Re^2: ", 6) == 0)
- X s += 6;
- X else
- X break;
- X }
- X#endif
- X
- X return s;
- X}
- X
- X
- X/*
- X * Hash the subjects (after eating the Re's off) for a quicker
- X * thread search later. We store the hashes for subjects in the
- X * index file for speed.
- X */
- X
- Xlong
- Xhash_s(s)
- Xchar *s;
- X{
- X long h = 0;
- X
- X while (*s)
- X h = h + (*s++ & 0xff);
- X
- X return h;
- X}
- X
- X
- Xparse_headers(fd, h)
- Xint fd;
- Xstruct header *h;
- X{
- X char buf[1024];
- X char *p, *q;
- X char flag;
- X char *ptr;
- X int found_from, found_subj;
- X int n;
- X
- X if ((n = read(fd, buf, 1024)) <= 0)
- X return FALSE;
- X
- X buf[n > 1023 ? 1023 : n] = '\0';
- X
- X p = buf;
- X while (p = index (p, '\n'))
- X if (*(p + 1) == '\n') {
- X *p = '\0';
- X break;
- X } else
- X ++p;
- X
- X p = buf;
- X
- X h->from[0] = '\0';
- X h->subject[0] = '\0';
- X h->nore = h->subject;
- X h->hash = 0;
- X
- X found_from = FALSE;
- X found_subj = FALSE;
- X while (1) {
- X q = p;
- X while (*p && *p != '\n') {
- X if ((unsigned char) *p & 0x7F < 32)
- X *p = ' ';
- X p++;
- X }
- X flag = *p;
- X *p++ = '\0';
- X
- X if ((!found_from) && (strncmp(q, "From: ", 6) == 0)) {
- X if (ptr = index (&q[6], '('))
- X ++ptr;
- X else
- X ptr = &q[6];
- X strncpy (h->from, ptr, MAX_FROM);
- X h->from[MAX_FROM-1] = '\0';
- X if (ptr = index (h->from, ')'))
- X *ptr = '\0';
- X } else if ((!found_subj) && (strncmp(q, "Subject: ", 9) == 0)) {
- X h->hash = hash_s(eat_re(&q[9]));
- X strncpy(h->subject, &q[9], MAX_SUBJ);
- X h->subject[MAX_SUBJ-1] = '\0';
- X h->nore = eat_re(h->subject);
- X }
- X
- X if ((!flag) || (found_from && found_subj))
- X break;
- X }
- X
- X return TRUE;
- X}
- X
- X
- X/*
- X * Write out a .tindex file. Write the group name first so if
- X * local indexing is done we can disambiguate between group name
- X * hash collisions by looking at the index file.
- X */
- Xvoid
- Xdump_index(group)
- Xchar *group;
- X{
- X int i;
- X char buf[200];
- X FILE *fp;
- X char *p, *q;
- X long l;
- X#ifndef USE_UID
- X char lockfn[64];
- X int lockfd;
- X
- X if (! local_index) {
- X#ifndef OSK
- X sprintf (lockfn, "/tmp/%-.10s", group);
- X lockfd = creat (lockfn, 0, 0444);
- X#else /* OSK */
- X sprintf (lockfn, "/dd/TMP/%-.20s", group);
- X for (p = lockfn; *p; ++p)
- X if (((unsigned char) *p >= 0x80) || ((!isalnum (*p)) && (*p != '/')))
- X *p = '_';
- X lockfd = create (lockfn, 0, 033);
- X#endif /* OSK */
- X if (lockfd < 0) {
- X sleep (1);
- X return;
- X }
- X }
- X#endif /* USE_UID */
- X
- X fp = fopen(index_file, "w");
- X if (fp == NULL)
- X#ifndef USE_UID
- X goto dump_index_finish;
- X#else /* USE_UID */
- X return;
- X#endif /* USE_UID */
- X
- X fprintf(fp, "%s\n", group);
- X fprintf(fp, "%d\n", num_arts());
- X for (i = 0; i < top; i++)
- X if (arts[i].thread != -2) {
- X p = arts[i].nore;
- X q = arts[i].subject;
- X l = p - q;
- X fprintf(fp, "%ld\n%s\n%s\n%ld\n%ld\n",
- X arts[i].artnum,
- X arts[i].subject,
- X arts[i].from,
- X arts[i].hash,
- X#if 0
- X (long) arts[i].nore - (long) arts[i].subject);
- X#else
- X l);
- X#endif
- X } else
- X ++complete_expire;
- X
- X fclose(fp);
- X#ifdef USE_UID
- X#ifndef OSK
- X chmod(index_file, 0644);
- X#else /* OSK */
- X chmod(index_file, 013);
- X#endif /* OSK */
- X#else /* USE_UID */
- Xdump_index_finish:
- X if (local_index)
- X#ifndef OSK
- X chmod(index_file, 0644);
- X#else /* OSK */
- X chmod(index_file, 013);
- X#endif /* OSK */
- X else if (lockfd != -1) {
- X close (lockfd);
- X#ifndef OSK
- X chmod (lockfn, 0666);
- X#endif /* OSK */
- X unlink (lockfn);
- X#ifndef OSK
- X chmod(index_file, 0666);
- X#else /* OSK */
- X chmod(index_file, 033);
- X#endif /* OSK */
- X }
- X#endif /* USE_UID */
- X}
- X
- X
- X/*
- X * strncpy that stops at a newline and null terminates
- X */
- X
- Xmy_strncpy(p, q, n)
- Xchar *p;
- Xchar *q;
- Xint n;
- X{
- X
- X while (n--) {
- X if (!*q || *q == '\n')
- X break;
- X *p++ = *q++;
- X }
- X *p = '\0';
- X}
- X
- X
- X/*
- X * Read in a .tindex file.
- X */
- Xvoid
- Xload_index()
- X{
- X int i;
- X long j;
- X char buf[200];
- X FILE *fp;
- X int first = TRUE;
- X
- X top = 0;
- X
- X fp = fopen(index_file, "r");
- X if (fp == NULL)
- X return;
- X
- X if (fgets(buf, 200, fp) == NULL
- X || fgets(buf, 200, fp) == NULL) {
- X fprintf(stderr, "one\n");
- X goto corrupt_index;
- X }
- X
- X i = atol(buf);
- X while (top < i) {
- X if (top >= max_art)
- X expand_art();
- X
- X arts[top].thread = -2;
- X arts[top].inthread = FALSE;
- X
- X if (fgets(buf, 200, fp) == NULL) {
- X fprintf(stderr, "two\n");
- X goto corrupt_index;
- X }
- X arts[top].artnum = atol(buf);
- X
- X if (fgets(buf, 200, fp) == NULL) {
- X fprintf(stderr, "three\n");
- X goto corrupt_index;
- X }
- X
- X my_strncpy(arts[top].subject, buf, MAX_SUBJ-1);
- X
- X if (fgets(buf, 200, fp) == NULL) {
- X fprintf(stderr, "four\n");
- X goto corrupt_index;
- X }
- X my_strncpy(arts[top].from, buf, MAX_FROM-1);
- X
- X if (fgets(buf, 200, fp) == NULL) {
- X fprintf(stderr, "five\n");
- X goto corrupt_index;
- X }
- X arts[top].hash = atol(buf);
- X
- X if (fgets(buf, 200, fp) == NULL) {
- X fprintf(stderr, "six\n");
- X goto corrupt_index;
- X }
- X
- X j = atol(buf);
- X#if 0
- X if (j < 0 || j > 100) {
- X#if 0
- X goto corrupt_index;
- X#else
- X arts[top].nore = eat_re(arts[top].subject);
- X#endif
- X } else
- X arts[top].nore = arts[top].subject + j;
- X#else
- X arts[top].nore = eat_re(arts[top].subject);
- X#endif
- X
- X top++;
- X }
- X
- X fclose(fp);
- X return;
- X
- Xcorrupt_index:
- X fprintf(stderr, "index file %s corrupt\n", index_file);
- X fprintf(stderr, "top = %d\n", top);
- X exit(1);
- X unlink(index_file);
- X top = 0;
- X}
- X
- X
- X/*
- X * Look in the local $HOME/.tindex (or wherever) directory for the
- X * index file for the given group. Hashing the group name gets
- X * a number. See if that #.1 file exists; if so, read first line.
- X * Group we want? If no, try #.2. Repeat until no such file or
- X * we find an existing file that matches our group.
- X */
- Xvoid
- Xfind_local_index(group)
- Xchar *group;
- X{
- X unsigned long h;
- X static char buf[200];
- X int i;
- X char *p;
- X FILE *fp;
- X
- X {
- X char *t = group;
- X
- X h = *t++;
- X while (*t)
- X h = (h << 1) + (*t++ & 0xff);
- X }
- X
- X i = 1;
- X while (1) {
- X sprintf(index_file, "%s/%lu.%d", indexdir, h, i);
- X fp = fopen(index_file, "r");
- X if (fp == NULL)
- X return;
- X
- X if (fgets(buf, 200, fp) == NULL) {
- X fclose(fp);
- X return;
- X }
- X fclose(fp);
- X
- X for (p = buf; *p && *p != '\n'; p++) ;
- X *p = '\0';
- X
- X if (strcmp(buf, group) == 0)
- X return;
- X
- X i++;
- X }
- X}
- X
- X
- X/*
- X * Run the index file updater only for the groups we've loaded.
- X */
- X
- Xdo_update() {
- X int i;
- X char group_path[200];
- X char *p;
- X#ifdef OSK
- X int len = 0;
- X#endif /* OSK */
- X time_t tim;
- X struct tm *tt;
- X
- X complete_count = 0;
- X complete_expire = 0;
- X
- X for (i = 0; i < local_top; i++) {
- X strcpy(group_path, active[my_group[i]].name);
- X for (p = group_path; *p; p++)
- X#ifndef OSK
- X if (*p == '.')
- X *p = '/';
- X#else /* OSK */
- X {
- X if (*p == '.') {
- X *p = '/';
- X len = 0;
- X } else if ((! isalnum (*p)) && (! index ("$_", *p)))
- X *p = '_';
- X if (++len > 26)
- X while (*(p + 1) && (*(p + 1) != '.'))
- X ++p;
- X }
- X#endif /* OSK */
- X
- X index_group(active[my_group[i]].name, group_path);
- X }
- X
- X time (&tim);
- X tt = localtime (&tim);
- X printf ("[%02d.%02d.%04d %2d:%2d] Collected %d articles",
- X tt -> tm_mday,
- X tt -> tm_mon + 1,
- X tt -> tm_year + 1900,
- X tt -> tm_hour,
- X tt -> tm_min,
- X complete_count);
- X
- X if (complete_expire)
- X printf (" (%d articles expired)", complete_expire);
- X putchar ('\n');
- X}
- __END__OF__THIS__FILE__
- if test -f 'curses.c' ; then
- echo 'File curses.c already exists, overwriting it'
- del 'curses.c'
- fi
- echo Extracting \"'curses.c'\"
- sed "s/^X//" >'curses.c' <<'__END__OF__THIS__FILE__'
- X
- X/*
- X * This is a screen management library borrowed with permission from the
- X * Elm mail system (a great mailer--I highly recommend it!).
- X *
- X * I've hacked this library to only provide what Tass needs.
- X *
- X * Original copyright follows:
- X */
- X
- X/*******************************************************************************
- X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
- X *
- X * Copyright (c) 1986 Dave Taylor
- X ******************************************************************************/
- X
- X#include <stdio.h>
- X#ifndef OSK
- X#include <curses.h>
- X#include <sys/ioctl.h>
- X#else /* OSK */
- X#include <termcap.h>
- X#include <sgstat.h>
- Xchar PC_, *UP, *BC;
- Xshort ospeed;
- X#endif /* OSK */
- X#include "tass.h"
- X
- X#define BACKSPACE '\b'
- X#define VERY_LONG_STRING 2500
- X
- Xint LINES=23;
- Xint COLS=80;
- X
- Xint inverse_okay = TRUE;
- X
- X/*
- X#ifdef BSD
- X# ifndef BSD4_1
- X# include <sgtty.h>
- X# else
- X# include <termio.h>
- X# endif
- X# else
- X# include <termio.h>
- X#endif
- X*/
- X
- X#include <ctype.h>
- X
- X/*
- X#ifdef BSD
- X#undef tolower
- X#endif
- X*/
- X
- X#define TTYIN 0
- X
- X#ifdef SHORTNAMES
- X# define _clearinverse _clrinv
- X# define _cleartoeoln _clrtoeoln
- X# define _cleartoeos _clr2eos
- X#endif
- X
- X#ifndef BSD
- X#ifndef OSK
- Xstruct termio _raw_tty,
- X _original_tty;
- X#else /* OSK */
- Xstruct sgbuf _raw_tty,
- X _original_tty;
- X#endif /* OSK */
- X#else
- X#define TCGETA TIOCGETP
- X#define TCSETAW TIOCSETP
- X
- Xstruct sgttyb _raw_tty,
- X _original_tty;
- X#endif
- X
- Xstatic int _inraw = 0; /* are we IN rawmode? */
- X
- X#define DEFAULT_LINES_ON_TERMINAL 24
- X#define DEFAULT_COLUMNS_ON_TERMINAL 80
- X
- Xstatic int _memory_locked = 0; /* are we IN memlock?? */
- X
- Xstatic int _intransmit; /* are we transmitting keys? */
- X
- Xstatic
- Xchar *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
- X *_setinverse, *_clearinverse, *_setunderline, *_clearunderline;
- X
- X# define K_UP 0
- X# define K_DOWN 1
- X# define K_LEFT 2
- X# define K_RIGHT 3
- X# define K_PUP 4
- X# define K_PDOWN 5
- X
- X# define K_MAX 6
- X
- Xstatic
- Xchar *_spckey[K_MAX];
- Xstatic
- Xchar *_spckeytc[K_MAX] = {
- X "ku", "kd", "kl", "kr", "kP", "kN"
- X};
- X
- Xstatic
- Xint _lines,_columns;
- X
- Xstatic char _terminal[1024]; /* Storage for terminal entry */
- Xstatic char _capabilities[1024]; /* String for cursor motion */
- X
- Xstatic char *ptr = _capabilities; /* for buffering */
- X
- Xint outchar(); /* char output for tputs */
- Xchar *tgetstr(), /* Get termcap capability */
- X *tgoto(); /* and the goto stuff */
- X
- XInitScreen()
- X{
- Xint tgetent(), /* get termcap entry */
- X err;
- Xchar termname[40];
- Xchar *strcpy(), *getenv();
- Xint i;
- X
- X if (getenv("TERM") == NULL) {
- X fprintf(stderr,
- X "TERM variable not set; Tass requires screen capabilities\n");
- X return(FALSE);
- X }
- X if (strcpy(termname, getenv("TERM")) == NULL) {
- X fprintf(stderr,"Can't get TERM variable\n");
- X return(FALSE);
- X }
- X if ((err = tgetent(_terminal, termname)) != 1) {
- X fprintf(stderr,"Can't get entry for TERM\n");
- X return(FALSE);
- X }
- X
- X /* load in all those pesky values */
- X _clearscreen = tgetstr("cl", &ptr);
- X _moveto = tgetstr("cm", &ptr);
- X _cleartoeoln = tgetstr("ce", &ptr);
- X _cleartoeos = tgetstr("cd", &ptr);
- X _lines = tgetnum("li");
- X _columns = tgetnum("co");
- X _setinverse = tgetstr("so", &ptr);
- X _clearinverse = tgetstr("se", &ptr);
- X _setunderline = tgetstr("us", &ptr);
- X _clearunderline = tgetstr("ue", &ptr);
- X
- X if (!_clearscreen) {
- X fprintf(stderr,
- X "Terminal must have clearscreen (cl) capability\n");
- X return(FALSE);
- X }
- X if (!_moveto) {
- X fprintf(stderr,
- X "Terminal must have cursor motion (cm)\n");
- X return(FALSE);
- X }
- X if (!_cleartoeoln) {
- X fprintf(stderr,
- X "Terminal must have clear to end-of-line (ce)\n");
- X return(FALSE);
- X }
- X if (!_cleartoeos) {
- X fprintf(stderr,
- X "Terminal must have clear to end-of-screen (cd)\n");
- X return(FALSE);
- X }
- X if (_lines == -1)
- X _lines = DEFAULT_LINES_ON_TERMINAL;
- X if (_columns == -1)
- X _columns = DEFAULT_COLUMNS_ON_TERMINAL;
- X
- X for (i = 0; i < K_MAX; ++i)
- X _spckey[i] = tgetstr (_spckeytc[i], &ptr);
- X
- X return(TRUE);
- X}
- X
- XScreenSize(lines, columns)
- Xint *lines, *columns;
- X{
- X /** returns the number of lines and columns on the display. **/
- X
- X if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
- X if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
- X
- X *lines = _lines - 1; /* assume index from zero*/
- X *columns = _columns; /* assume index from one */
- X}
- X
- XClearScreen()
- X{
- X /* clear the screen: returns -1 if not capable */
- X
- X tputs(_clearscreen, 1, outchar);
- X fflush(stdout); /* clear the output buffer */
- X}
- X
- XMoveCursor(row, col)
- Xint row, col;
- X{
- X /** move cursor to the specified row column on the screen.
- X 0,0 is the top left! **/
- X
- X char *stuff, *tgoto();
- X
- X stuff = tgoto(_moveto, col, row);
- X tputs(stuff, 1, outchar);
- X fflush(stdout);
- X}
- X
- XCleartoEOLN()
- X{
- X /** clear to end of line **/
- X
- X tputs(_cleartoeoln, 1, outchar);
- X fflush(stdout); /* clear the output buffer */
- X}
- X
- XCleartoEOS()
- X{
- X /** clear to end of screen **/
- X
- X tputs(_cleartoeos, 1, outchar);
- X fflush(stdout); /* clear the output buffer */
- X}
- X
- XStartInverse()
- X{
- X /** set inverse video mode **/
- X
- X if (_setinverse && inverse_okay)
- X tputs(_setinverse, 1, outchar);
- X/* fflush(stdout); */
- X}
- X
- X
- XEndInverse()
- X{
- X /** compliment of startinverse **/
- X
- X if (_clearinverse && inverse_okay)
- X tputs(_clearinverse, 1, outchar);
- X/* fflush(stdout); */
- X}
- X
- X#if 0
- XStartUnderline()
- X{
- X /** start underline mode **/
- X
- X if (!_setunderline)
- X return(-1);
- X
- X tputs(_setunderline, 1, outchar);
- X fflush(stdout);
- X return(0);
- X}
- X
- X
- XEndUnderline()
- X{
- X /** the compliment of start underline mode **/
- X
- X if (!_clearunderline)
- X return(-1);
- X
- X tputs(_clearunderline, 1, outchar);
- X fflush(stdout);
- X return(0);
- X}
- X#endif
- X
- XRawState()
- X{
- X /** returns either 1 or 0, for ON or OFF **/
- X
- X return( _inraw );
- X}
- X
- XRaw(state)
- Xint state;
- X{
- X /** state is either TRUE or FALSE, as indicated by call **/
- X
- X if (state == FALSE && _inraw) {
- X#ifndef OSK
- X (void) ioctl(TTYIN, TCSETAW, &_original_tty);
- X#else /* OSK */
- X (void) _ss_opt (TTYIN, &_original_tty);
- X#endif /* OSK */
- X _inraw = 0;
- X }
- X else if (state == TRUE && ! _inraw) {
- X
- X#ifndef OSK
- X (void) ioctl(TTYIN, TCGETA, &_original_tty); /** current setting **/
- X
- X (void) ioctl(TTYIN, TCGETA, &_raw_tty); /** again! **/
- X#ifdef BSD
- X _raw_tty.sg_flags &= ~(ECHO | CRMOD); /* echo off */
- X _raw_tty.sg_flags |= CBREAK; /* raw on */
- X#else
- X _raw_tty.c_lflag &= ~(ICANON | ECHO); /* noecho raw mode */
- X
- X _raw_tty.c_cc[VMIN] = '\01'; /* minimum # of chars to queue */
- X _raw_tty.c_cc[VTIME] = '\0'; /* minimum time to wait for input */
- X
- X#endif
- X (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
- X#else /* OSK */
- X (void) _gs_opt (TTYIN, &_original_tty);
- X _raw_tty = _original_tty;
- X _raw_tty.sg_echo = 0;
- X _raw_tty.sg_pause = 0;
- X _raw_tty.sg_alf = 0;
- X _raw_tty.sg_psch = 0;
- X _raw_tty.sg_eofch = 0;
- X
- X (void) _ss_opt (TTYIN, &_raw_tty);
- X#endif /* OSK */
- X
- X _inraw = 1;
- X }
- X}
- X
- Xint
- XReadCh()
- X{
- X /** read a character with Raw mode set! **/
- X
- X register int result;
- X char ch;
- X register int i, j, n;
- X register char *spc;
- X
- X spc = NULL;
- X do {
- X if (spc) {
- X#ifdef OSK
- X tsleep (4);
- X if (_gs_rdy (0) < 1)
- X tsleep (50 | (1 << 31));
- X if (_gs_rdy (0) < 1)
- X#else /* OSK */
- X#ifdef FIONREAD
- X#define CH_READ FIONREAD
- X#else /* FIONREAD */
- X#ifdef TCRDCHK
- X#define CH_READ TCRDCHK
- X#else /* TCRDCHK */
- X Panic!
- X#endif /* TCRDCHK */
- X#endif /* FIONREAD */
- X int tmp;
- X
- X ioctl (0, CH_READ, &tmp);
- X if (tmp < 1)
- X nap (200);
- X ioctl (0, CH_READ, &tmp);
- X if (tmp < 1)
- X#endif /* OSK */
- X spc = NULL;
- X }
- X if ((result = read(0, &ch, 1)) != 1)
- X break;
- X if (!spc) {
- X for (i = 0; i < K_MAX; ++i)
- X if (_spckey[i] && (_spckey[i][0] == ch)) {
- X spc = _spckey[i];
- X n = 1;
- X break;
- X }
- X } else if (ch != spc[n]) {
- X for (j = 0; j < K_MAX; ++j)
- X if (!_spckey[j])
- X continue;
- X else if (spc[0]) {
- X if ((!strncmp (spc, _spckey[j], n - 1)) && (_spckey[j][n] == ch))
- X break;
- X } else if (spc[0] == _spckey[j][0]) {
- X if (n > 1) {
- X if ((!strncmp (spc + 1, _spckey[j] + 1, n - 2)) && (_spckey[j][n] == ch))
- X break;
- X } else if (_spckey[j][n] == ch)
- X break;
- X }
- X if (j < K_MAX) {
- X spc = _spckey[j];
- X i = j;
- X ++n;
- X } else {
- X spc = NULL;
- X result = -1;
- X }
- X } else
- X ++n;
- X if (spc && (!spc[n])) {
- X spc = NULL;
- X switch (i) {
- X case K_UP:
- X ch = ctrl('P');
- X break;
- X case K_DOWN:
- X ch = ctrl('N');
- X break;
- X case K_LEFT:
- X ch = ctrl('B');
- X break;
- X case K_RIGHT:
- X ch = ctrl('F');
- X break;
- X case K_PUP:
- X ch = ctrl('Z');
- X break;
- X case K_PDOWN:
- X ch = ctrl('V');
- X break;
- X }
- X }
- X } while (spc || (result < 0));
- X return((result <= 0 ) ? EOF : ch & 0x7F);
- X}
- X
- X
- Xoutchar(c)
- Xchar c;
- X{
- X /** output the given character. From tputs... **/
- X /** Note: this CANNOT be a macro! **/
- X
- X putc(c, stdout);
- X}
- X
- X#ifdef NO_NAP
- Xnap (n)
- Xint n;
- X{
- X int t;
- X
- X for (t = 100 * n; t > 0; --t)
- X ;
- X}
- X#endif /* NO_NAP */
- __END__OF__THIS__FILE__
- if test -f 'group.c' ; then
- echo 'File group.c already exists, overwriting it'
- del 'group.c'
- fi
- echo Extracting \"'group.c'\"
- sed "s/^X//" >'group.c' <<'__END__OF__THIS__FILE__'
- X
- X
- X#include <stdio.h>
- X#include <signal.h>
- X#ifdef REGEXP
- X#include <regexp.h>
- X#endif /* REGEXP */
- X#ifdef OSK
- X#include <ctype.h>
- X#endif /* OSK */
- X#include "tass.h"
- X
- X#ifdef GET_DIST
- Xextern char *index ();
- X#endif /* GET_DIST */
- X
- Xint index_point;
- Xint first_subj_on_screen;
- Xint last_subj_on_screen;
- Xchar subject_search_string[LEN+1]; /* last search pattern */
- Xextern int cur_groupnum;
- Xextern int last_resp; /* page.c */
- Xextern int this_resp; /* page.c */
- Xextern int space_mode; /* select.c */
- Xextern char *cvers;
- X
- Xchar *glob_group;
- X
- X
- X#ifdef SIGTSTP
- Xvoid
- Xgroup_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, group_susp);
- X Raw(TRUE);
- X mail_setup();
- X show_group_page(glob_group, TRUE);
- X}
- X#endif
- X
- X
- Xgroup_page(group)
- Xchar *group;
- X{
- X char ch;
- X int i, n;
- X char group_path[200];
- X char *p;
- X char buf[200];
- X
- X glob_group = group;
- X
- X strcpy(group_path, group); /* turn comp.unix.amiga into */
- X for (p = group_path; *p; p++) /* comp/unix/amiga */
- X if (*p == '.')
- X *p = '/';
- X#ifdef OSK
- X else if ((!isalnum (*p)) || ((unsigned char) *p >= 0x80))
- X *p = '_';
- X#endif /* OSK */
- X
- X last_resp = -1;
- X this_resp = -1;
- X index_group(group, group_path); /* update index file */
- X read_newsrc_line(group); /* get sequencer information */
- X
- X if (space_mode) {
- X for (i = 0; i < top_base; i++)
- X if (new_responses(i))
- X break;
- X if (i < top_base)
- X index_point = i;
- X else
- X index_point = top_base - 1;
- X } else
- X index_point = top_base - 1;
- X
- X show_group_page(group, TRUE);
- 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') { /* 0 goes to basenote */
- X prompt_subject_num(ch, group);
- X } else switch (ch) {
- 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 break;
- X
- X case 's': /* subscribe to this group */
- X subscribe(group, ':', my_group[cur_groupnum],
- X TRUE);
- X sprintf(buf, "subscribed to %s", group);
- X info_message(buf);
- X break;
- X
- X case 'u': /* unsubscribe to this group */
- X subscribe(group, '!', my_group[cur_groupnum],
- X TRUE);
- X sprintf(buf, "unsubscribed to %s", group);
- X info_message(buf);
- X break;
- X
- X case 'g': /* choose a new group by name */
- X n = choose_new_group();
- X if (n >= 0 && n != cur_groupnum) {
- X fix_new_highest(cur_groupnum);
- X cur_groupnum = n;
- X index_point = -3;
- X goto group_done;
- X }
- X break;
- X
- X case 'c': /* catchup--mark all articles as read */
- X if (prompt_yn("Mark everything as read? (y/n): ")) {
- X for (n = 0; n < top; n++)
- X arts[n].unread = 0;
- X show_group_page(group, FALSE);
- X info_message("All articles marked as read");
- X }
- X break;
- X
- X#ifdef USE_ARROW
- X case 27: /* common arrow keys */
- X ch = ReadCh();
- X if (ch == '[' || ch == 'O')
- X ch = ReadCh();
- X switch (ch) {
- X case 'A':
- X case 'D':
- X case 'i':
- X goto group_up;
- X
- X case 'B':
- X case 'I':
- X case 'C':
- X goto group_down;
- X }
- X break;
- X#endif /* USE_ARROW */
- X
- X case 'n': /* next group */
- X clear_message();
- X if (cur_groupnum + 1 >= local_top)
- X info_message("No more groups");
- X else {
- X fix_new_highest(cur_groupnum);
- X cur_groupnum++;
- X index_point = -3;
- X space_mode = FALSE;
- X goto group_done;
- X }
- X break;
- X
- X case 'p': /* previous group */
- X clear_message();
- X if (cur_groupnum <= 0)
- X info_message("No previous group");
- X else {
- X fix_new_highest(cur_groupnum);
- X cur_groupnum--;
- X index_point = -3;
- X space_mode = FALSE;
- X goto group_done;
- X }
- X break;
- X
- X case ' ':
- X if (top_base <= 0)
- X info_message("*** No Articles ***");
- X else if (last_subj_on_screen == top_base)
- X info_message("*** End of Articles ***");
- X else
- X clear_message();
- X break;
- X
- X case '\t':
- X fix_new_highest(cur_groupnum);
- X space_mode = TRUE;
- X
- X if (index_point < 0
- X || (n=next_unread((int) base[index_point]))<0) {
- X for (i = cur_groupnum+1;
- X i < local_top; i++)
- X if (unread[i] > 0)
- X break;
- X if (i >= local_top)
- X goto group_done;
- X
- X cur_groupnum = i;
- X index_point = -3;
- X goto group_done;
- X }
- X index_point = show_page(n, group, group_path);
- X if (index_point < 0)
- X goto group_done;
- X show_group_page(group, TRUE);
- X break;
- X
- X
- X case 'N': /* go to next unread article */
- X if (index_point < 0) {
- X info_message("No next unread article");
- X break;
- X }
- X
- X n = next_unread( (int) base[index_point]);
- X if (n == -1)
- X info_message("No next unread article");
- X else {
- X index_point =
- X show_page(n, group, group_path, TRUE);
- X if (index_point < 0) {
- X fix_new_highest(cur_groupnum);
- X space_mode = FALSE;
- X goto group_done;
- X }
- X show_group_page(group, TRUE);
- X }
- X break;
- X
- X case 'P': /* go to previous unread article */
- X if (index_point < 0) {
- X info_message("No previous unread article");
- X break;
- X }
- X
- X n = prev_response( (int) base[index_point]);
- X n = prev_unread(n);
- X if (n == -1)
- X info_message("No previous unread article");
- X else {
- X index_point =
- X show_page(n, group, group_path, TRUE);
- X if (index_point < 0) {
- X fix_new_highest(cur_groupnum);
- X space_mode = FALSE;
- X goto group_done;
- X }
- X show_group_page(group, TRUE);
- X }
- X break;
- X
- X case 'w': /* post a basenote */
- X post_base(group);
- X update_newsrc(group, my_group[cur_groupnum]);
- X index_group(group, group_path);
- X read_newsrc_line(group);
- X index_point = top_base - 1;
- X show_group_page(group, TRUE);
- X break;
- X
- X case 't': /* return to group selection page */
- X case ctrl('B'): /* cursor key */
- X fix_new_highest(cur_groupnum);
- X goto group_done;
- X
- X#ifndef OSK
- X case '\r':
- X#else /* OSK */
- X case '\l':
- X#endif /* OSK */
- X case '\n': /* read current basenote */
- X case ctrl('F'): /* cursor key */
- X if (index_point < 0) {
- X info_message("*** No Articles ***");
- X break;
- X }
- X index_point = show_page((int) base[index_point],
- X group, group_path, TRUE);
- X if (index_point < 0) {
- X fix_new_highest(cur_groupnum);
- X space_mode = FALSE;
- X goto group_done;
- X }
- X show_group_page(group, TRUE);
- X break;
- X
- X case ctrl('D'): /* page down */
- X case ctrl('V'): /* full page down */
- X if (!top_base || index_point == top_base - 1)
- X break;
- X
- X erase_subject_arrow();
- X index_point += (ch == ctrl('V')) ?
- X NOTESLINES :
- X NOTESLINES / 2;
- X if (index_point >= top_base)
- X index_point = top_base - 1;
- X
- X if (index_point < first_subj_on_screen
- X || index_point >= last_subj_on_screen)
- X show_group_page(group, TRUE);
- X else
- X draw_subject_arrow();
- X break;
- X
- X case '-': /* go to last viewed article */
- X if (this_resp < 0) {
- X info_message("No last message");
- X break;
- X }
- X index_point = show_page(this_resp,
- X group, group_path, TRUE);
- X if (index_point < 0) {
- X fix_new_highest(cur_groupnum);
- X space_mode = FALSE;
- X goto group_done;
- X }
- X show_group_page(group, TRUE);
- X break;
- X
- X case ctrl('U'): /* page up */
- X case ctrl('Z'): /* full page up */
- X if (!top_base)
- X break;
- X
- X erase_subject_arrow();
- X index_point -= (ch == ctrl('Z')) ?
- X NOTESLINES :
- X NOTESLINES / 2;
- X if (index_point < 0)
- X index_point = 0;
- X if (index_point < first_subj_on_screen
- X || index_point >= last_subj_on_screen)
- X show_group_page(group, TRUE);
- X else
- X draw_subject_arrow();
- X break;
- X
- X case 'v':
- X info_message(cvers);
- X break;
- X
- X case '!':
- X shell_escape();
- X show_group_page(group, TRUE);
- X break;
- X
- X case ctrl('N'):
- X case 'j': /* line down */
- X#ifdef USE_ARROW
- Xgroup_down:
- X#endif /* USE_ARROW */
- X if (!top_base || index_point + 1 >= top_base)
- X break;
- X
- X erase_subject_arrow();
- X index_point++;
- X if (index_point >= last_subj_on_screen)
- X show_group_page(group, FALSE);
- X else
- X draw_subject_arrow();
- X break;
- X
- X case ctrl('P'):
- X case 'k': /* line up */
- X#ifdef USE_ARROW
- Xgroup_up:
- X#endif /* USE_ARROW */
- X if (!top_base || !index_point)
- X break;
- X
- X erase_subject_arrow();
- X index_point--;
- X if (index_point + 1 <= first_subj_on_screen)
- X show_group_page(group, FALSE);
- X else
- X draw_subject_arrow();
- X break;
- X
- X case ctrl('R'):
- X case ctrl('L'):
- X case ctrl('W'):
- X case 'i': /* return to index */
- X show_group_page(group, FALSE);
- X break;
- X
- X case '/': /* forward search */
- X search_subject(TRUE, group);
- X break;
- X
- X case '?': /* backward search */
- X search_subject(FALSE, group);
- X break;
- X
- X#ifndef OSK
- X case 'q': /* quit */
- X index_point = -2;
- X fix_new_highest(cur_groupnum);
- X space_mode = FALSE;
- X goto group_done;
- X#endif /* OSK */
- X
- X case 'h':
- X tass_group_help();
- X show_group_page(group, TRUE);
- X break;
- X
- X default:
- X info_message("Bad command. Type 'h' for help.");
- X }
- X }
- X
- Xgroup_done:
- X update_newsrc(group, my_group[cur_groupnum]);
- X
- X if (index_point == -2)
- X tass_done(0);
- X}
- X
- X
- X/*
- X * Correct highest[] for the group selection page display since
- X * new articles may have been read or marked unread
- X */
- X
- Xfix_new_highest(groupnum)
- Xint groupnum;
- X{
- X int i;
- X int sum = 0;
- X
- X for (i = 0; i < top; i++)
- X if (arts[i].unread)
- X sum++;
- X
- X unread[groupnum] = sum;
- X}
- X
- X
- Xshow_mail () {
- X if (mail_check()) { /* you have mail message in */
- X MoveCursor(0, COLS - 14); /* upper right */
- X printf("you have mail");
- X fflush (stdout);
- X }
- X}
- X
- Xshow_group_page(group, clr)
- Xchar *group;
- Xint clr;
- X{
- X int i;
- X int n;
- X char resps[10];
- X char new_resps;
- X int respnum;
- X
- X#ifdef SIGTSTP
- X signal(SIGTSTP, group_susp);
- X#endif
- X
- X if (clr) {
- X ClearScreen();
- X printf("%s\r\012", nice_time()); /* time in upper left */
- X center_line(1, group);
- X }
- X
- X show_mail ();
- X
- X MoveCursor(INDEX_TOP, 0);
- X
- X first_subj_on_screen = (index_point / NOTESLINES) * NOTESLINES;
- X if (first_subj_on_screen < 0)
- X first_subj_on_screen = 0;
- X
- X last_subj_on_screen = first_subj_on_screen + NOTESLINES;
- X if (last_subj_on_screen >= top_base) {
- X last_subj_on_screen = top_base;
- X first_subj_on_screen = top_base - NOTESLINES;
- X
- X if (first_subj_on_screen < 0)
- X first_subj_on_screen = 0;
- X }
- X
- X for (i = first_subj_on_screen; i < last_subj_on_screen; i++) {
- X if (new_responses(i))
- X new_resps = '+';
- X else
- X new_resps = ' ';
- X
- X n = nresp(i);
- X if (n)
- X sprintf(resps, "%4d", n);
- X else
- X strcpy(resps, " ");
- X
- X respnum = base[i];
- X
- X MoveCursor(INDEX_TOP + i - first_subj_on_screen, 3);
- X printf("%4d %c %s", i + 1, new_resps, arts[respnum].subject);
- X CleartoEOLN ();
- X MoveCursor(INDEX_TOP + i - first_subj_on_screen, COLS - 35);
- X printf ("%s %-.30s", resps, arts[respnum].from);
- X MoveCursor(INDEX_TOP + i - first_subj_on_screen, COLS - 1);
- X CleartoEOLN ();
- X }
- X
- X if (top_base <= 0)
- X info_message("*** No Articles ***");
- X else if (last_subj_on_screen == top_base)
- X info_message("*** End of Articles ***");
- X
- X if (top_base > 0)
- X draw_subject_arrow();
- X}
- X
- Xdraw_subject_arrow() {
- X
- X draw_arrow(INDEX_TOP + (index_point-first_subj_on_screen) );
- X}
- X
- Xerase_subject_arrow() {
- X
- X erase_arrow(INDEX_TOP + (index_point-first_subj_on_screen) );
- X}
- X
- X
- Xprompt_subject_num(ch, group)
- Xchar ch;
- Xchar *group;
- X{
- Xint num;
- X
- X
- X clear_message();
- X
- X if ((num = parse_num(ch, "Read article> ")) == -1) {
- X clear_message();
- X return FALSE;
- X }
- X num--; /* index from 0 (internal) vs. 1 (user) */
- X
- X if (num >= top_base)
- X num = top_base - 1;
- X
- X if (num >= first_subj_on_screen
- X && num < last_subj_on_screen) {
- X erase_subject_arrow();
- X index_point = num;
- X draw_subject_arrow();
- X } else {
- X index_point = num;
- X show_group_page(group, TRUE);
- X }
- X}
- X
- Xvoid
- Xsearch_subject(forward, group)
- Xint forward;
- Xchar *group;
- X{
- X char buf[LEN+1];
- X int i;
- X#ifndef REGEXP
- X extern char *regcmp();
- X extern char *regex();
- X char *re;
- X#else /* REGEXP */
- X regexp *re;
- X#endif /* REGEXP */
- X char *prompt;
- X
- X clear_message();
- X
- X if (forward)
- X prompt = "/";
- X else
- X prompt = "?";
- X
- X if (!parse_string(prompt, buf))
- X return;
- X
- X if (strlen(buf))
- X strcpy(subject_search_string, buf);
- X else if (!strlen(subject_search_string)) {
- X info_message("No search pattern");
- X return;
- X }
- X
- X i = index_point;
- X
- X glob_name(subject_search_string, buf);
- X
- X#ifndef REGEXP
- X if ((re = regcmp(buf, NULL)) == NULL) {
- X#else /* REGEXP */
- X if ((re = regcomp (buf)) == NULL) {
- X#endif /* REGEXP */
- X info_message("Bad search pattern");
- X return;
- X }
- X
- X do {
- X if (forward)
- X i++;
- X else
- X i--;
- X
- X if (i >= top_base)
- X i = 0;
- X if (i < 0)
- X i = top_base - 1;
- X
- X#ifndef REGEXP
- X if (regex(re, arts[ base[i] ].subject) != NULL) {
- X#else /* REGEXP */
- X if (regexec (re, arts[ base[i] ].subject) != NULL) {
- X#endif /* REGEXP */
- X if (i >= first_subj_on_screen
- X && i < last_subj_on_screen) {
- X erase_subject_arrow();
- X index_point = i;
- X draw_subject_arrow();
- X } else {
- X index_point = i;
- X show_group_page(group, TRUE);
- X }
- X return;
- X }
- X } while (i != index_point);
- X
- X info_message("No match");
- X}
- X
- X
- X/*
- X * Post an original article (not a followup)
- X */
- X
- Xpost_base(group)
- Xchar *group;
- X{
- X FILE *fp;
- X char nam[100];
- X char ch;
- X char subj[LEN+1];
- X char buf[200];
- X int line;
- X#ifdef GET_DIST
- X char *ptr;
- X#endif /* GET_DIST */
- X
- X if (!parse_string("Subject: ", subj))
- X return(FALSE);
- X if (subj[0] == '\0')
- X return(FALSE);
- 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: %s\n", subj);
- X fprintf(fp, "Newsgroups: %s\n", group);
- X#ifndef GET_DIST
- X/* fprintf(fp, "Distribution: \n"); */
- X line = 2;
- X#else /* GET_DIST */
- X strcpy (buf, group);
- X if (ptr = index (buf, '.'))
- X *ptr = '\0';
- X fprintf(fp, "Distribution: %s\n", buf);
- X line = 3;
- X#endif /* GET_DIST */
- X if (*my_org) {
- X fprintf(fp, "Organization: %s\n", my_org);
- X ++line;
- X }
- X fprintf(fp, "\n");
- X ++line;
- 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_base_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_base_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
- X/*
- X * Return the number of unread articles there are within a thread
- X */
- X
- Xnew_responses(thread)
- Xint thread;
- X{
- X int i;
- X int sum = 0;
- X
- X for (i = base[thread]; i >= 0; i = arts[i].thread)
- X if (arts[i].unread)
- X sum++;
- X
- X return sum;
- X}
- X
- Xvoid
- Xtass_group_help() {
- X char ch;
- X
- Xgroup_help_start:
- X
- X ClearScreen();
- X center_line(0, TASS_HEADER);
- X center_line(1, "Index Page Commands (page 1 of 2)");
- X
- X MoveCursor(3, 0);
- X
- X printf("4 Select article 4\r\012");
- X printf("^D, ^V half / full Page down\r\012");
- X printf("^U, ^Z half / full Page up\r\012");
- X printf("<CR> Read current article\r\012");
- X printf("<TAB> View next unread article or group\r\012");
- X printf("c Mark all articles as read\r\012");
- X printf("g Choose a new group by name\r\012");
- X printf("j Down a line\r\012");
- X printf("k Up a line\r\012");
- X printf("n Go to next group\r\012");
- X printf("N Go to next unread article\r\012");
- X printf("p Go to previous group\r\012");
- X printf("P Go to previous unread article\r\012");
- X printf("q Quit\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, "Index Page Commands (page 2 of 2)");
- X
- X MoveCursor(3, 0);
- X
- X printf("s Subscribe to this group\r\012");
- X printf("t Return to group selection index\r\012");
- X printf("u Unsubscribe to this group\r\012");
- X printf("w Post an article\r\012");
- X printf("/ Search forward for subject\r\012");
- X printf("? Search backward for subject\r\012");
- X printf("- Show last message\r\012");
- X
- X center_line(LINES, "-- hit any key --");
- X ch = ReadCh();
- X if (ch == 'b')
- X goto group_help_start;
- X}
- __END__OF__THIS__FILE__
- exit 0
- : end of shell archive
-
- --
- Frank Kaefer # fkk@stasys.sta.sub.org # Starnberg, Germany
-