home *** CD-ROM | disk | FTP | other *** search
- From: skrenta@blekko.commodore.com (Rich Skrenta)
- Newsgroups: alt.sources
- Subject: Tass newsreader (part 1 of 2)
- Message-ID: <145@blekko.commodore.com>
- Date: 14 Feb 91 19:33:07 GMT
-
-
- # This is a shell archive. Remove anything before this line,
- # then unpack it by saving it in a file and typing "sh file".
- #
- # This archive contains:
- # COPYRIGHT Makefile Todo art.c
- # curses.c group.c mail.c main.c
- # misc.c
- #
-
- echo x - COPYRIGHT
- cat >COPYRIGHT <<'@EOF'
- /*
- * Tass, a visual Usenet news reader
- * (c) Copyright 1990 by Rich Skrenta
- *
- * Distribution agreement:
- *
- * You may freely copy or redistribute this software, so long
- * as there is no profit made from its use, sale, trade or
- * reproduction. You may not change this copyright notice,
- * and it must be included prominently in any copy made.
- */
- @EOF
-
- chmod 600 COPYRIGHT
-
- echo x - Makefile
- cat >Makefile <<'@EOF'
-
- # Edit the defines in tass.h to point tass at the correct news libdir
-
- #
- # For Berkeley systems:
- #
- # CFLAGS= -DBSD
- # LIBS= -lcurses -ltermcap
-
- # art.c needs to know whether readdir returns struct dirent or
- # struct direct. You don't need to change anything if:
- # you're bsd and have BSD defined
- # you're Xenix 286
- # you're SCO Unix and have -UM_XENIX defined
- # you use struct dirent
-
- #
- # For System V and Xenix:
- #
- CFLAGS=-g
- LIBS= -lcurses -lgen
-
-
- OBJECTS = curses.o art.o group.o mail.o main.o misc.o page.o \
- prompt.o screen.o select.o time.o
-
- tass: $(OBJECTS)
- cc $(CFLAGS) -o tass $(OBJECTS) $(LIBS)
-
- shar:
- -mv -f ../tass.shar ../tass.shar-
- shar -v [A-Z]* *.[ch] > ../tass.shar
-
-
- art.o: art.c tass.h
- curses.o: curses.c
- group.o: group.c tass.h
- mail.o: mail.c
- main.o: main.c tass.h
- misc.o: misc.c tass.h
- page.o: page.c tass.h
- prompt.o: prompt.c tass.h
- screen.o: screen.c tass.h
- select.o: select.c tass.h
- time.o: time.c
- @EOF
-
- chmod 644 Makefile
-
- echo x - Todo
- cat >Todo <<'@EOF'
- make initial .newsrc just be created but contain nothing--must
- subscribe
-
- find_new_to doesnn't seem to work in mail_to_someone()
- @EOF
-
- chmod 644 Todo
-
- echo x - art.c
- cat >art.c <<'@EOF'
-
-
- #include <stdio.h>
- #include <signal.h>
- #include "tass.h"
-
-
- /* Hopefully one of these is right for you. */
-
- #ifdef BSD
- # include <sys/types.h>
- # include <sys/dir.h>
- # define DIR_BUF struct direct
- # define D_LENGTH d_namlen
- #endif
- #ifdef M_XENIX
- # include <sys/ndir.h>
- # define DIR_BUF struct direct
- # define D_LENGTH d_namlen
- #endif
- #ifndef DIR_BUF
- # include <sys/types.h>
- # include <dirent.h>
- # define DIR_BUF struct dirent
- # define D_LENGTH d_reclen
- #endif
-
-
- char index_file[LEN+1];
- char *glob_art_group;
-
-
- #ifdef SIGTSTP
- void
- art_susp(i)
- int i;
- {
-
- Raw(FALSE);
- putchar('\n');
- signal(SIGTSTP, SIG_DFL);
- kill(0, SIGTSTP);
-
- signal(SIGTSTP, art_susp);
- Raw(TRUE);
-
- mail_setup();
- ClearScreen();
- MoveCursor(LINES, 0);
- printf("Group %s... ", glob_art_group);
- fflush(stdout);
- }
- #endif
-
-
- /*
- * Convert a string to a long, only look at first n characters
- */
-
- my_atol(s, n)
- char *s;
- int n;
- {
- long ret = 0;
-
- while (*s && n--) {
- if (*s >= '0' && *s <= '9')
- ret = ret * 10 + (*s - '0');
- else
- return -1;
- s++;
- }
-
- return ret;
- }
-
-
- /*
- * Construct the pointers to the basenotes of each thread
- * arts[] contains every article in the group. inthread is
- * set on each article that is after the first article in the
- * thread. Articles which have been expired have their thread
- * set to -2.
- */
-
- find_base() {
- int i;
-
- top_base = 0;
-
- for (i = 0; i < top; i++)
- if (!arts[i].inthread && arts[i].thread != -2) {
- if (top_base >= max_art)
- expand_art();
- base[top_base++] = i;
- }
- }
-
-
- /*
- * Count the number of non-expired articles in arts[]
- */
-
- num_arts() {
- int sum = 0;
-
- int i;
-
- for (i = 0; i < top; i++)
- if (arts[i].thread != -2)
- sum++;
-
- return sum;
- }
-
-
- /*
- * Do we have an entry for article art?
- */
-
- valid_artnum(art)
- long art;
- {
- int i;
-
- for (i = 0; i < top; i++)
- if (arts[i].artnum == art)
- return i;
-
- return -1;
- }
-
-
- /*
- * Return TRUE if arts[] contains any expired articles
- * (articles we have an entry for which don't have a corresponding
- * article file in the spool directory)
- */
-
- purge_needed() {
- int i;
-
- for (i = 0; i < top; i++)
- if (arts[i].thread == -2)
- return TRUE;
-
- return FALSE;
- }
-
-
- /*
- * Main group indexing routine. Group should be the name of the
- * newsgroup, i.e. "comp.unix.amiga". group_path should be the
- * same but with the .'s turned into /'s: "comp/unix/amiga"
- *
- * Will read any existing index, create or incrementally update
- * the index by looking at the articles in the spool directory,
- * and attempt to write a new index if necessary.
- */
-
- index_group(group, group_path)
- char *group;
- char *group_path;
- {
- int modified;
-
- glob_art_group = group;
-
- #ifdef SIGTSTP
- signal(SIGTSTP, art_susp);
- #endif
-
- if (!update) {
- clear_message();
- MoveCursor(LINES, 0);
- printf("Group %s... ", group);
- fflush(stdout);
- }
-
- if (local_index)
- find_local_index(group);
- else
- sprintf(index_file, "%s/%s/.tindex", SPOOLDIR, group_path);
-
- load_index();
- modified = read_group(group_path);
- make_threads();
- if (modified || purge_needed()) {
- if (local_index) { /* writing index in home directory */
- setuid(real_uid); /* so become them */
- setgid(real_gid);
- }
- dump_index(group);
- if (local_index) {
- setuid(tass_uid);
- setgid(tass_gid);
- }
- }
- find_base();
-
- if (modified && !update)
- clear_message();
- }
-
-
- /*
- * Longword comparison routine for the qsort()
- */
-
- base_comp(a, b)
- long *a;
- long *b;
- {
-
- if (*a < *b)
- return -1;
- if (*a > *b)
- return 1;
- return 0;
- }
-
-
- /*
- * Read the article numbers existing in a group's spool directory
- * into base[] and sort them. base_top is one past top.
- */
-
- scan_dir(group)
- char *group;
- {
- DIR *d;
- DIR_BUF *e;
- long art;
- char buf[200];
-
- top_base = 0;
-
- sprintf(buf, "%s/%s", SPOOLDIR, group);
-
- d = opendir(buf);
- if (d != NULL) {
- while ((e = readdir(d)) != NULL) {
- art = my_atol(e->d_name, e->D_LENGTH);
- if (art >= 0) {
- if (top_base >= max_art)
- expand_art();
- base[top_base++] = art;
- }
- }
- closedir(d);
- }
-
- qsort(base, top_base, sizeof(long), base_comp);
- }
-
-
- /*
- * Index a group. Assumes any existing index has already been
- * loaded.
- */
-
- read_group(group)
- char *group;
- {
- char buf[200];
- int fd;
- long art;
- int count;
- int modified = FALSE;
- int respnum;
- int i;
-
- scan_dir(group); /* load article numbers into base[] */
-
- count = 0;
-
- for (i = 0; i < top_base; i++) { /* for each article # */
- art = base[i];
-
- /*
- * Do we already have this article in our index? Change thread from
- * -2 to -1 if so and skip the header eating.
- */
-
- if ((respnum = valid_artnum(art)) >= 0) {
- arts[respnum].thread = -1;
- arts[respnum].unread = 1;
- continue;
- }
-
- if (!modified) {
- modified = TRUE; /* we've modified the index */
- /* it will need to be re-written */
- #if 0
- if (!update) {
- MoveCursor(LINES, 0);
- fputs("Indexing... ", stdout);
- fflush(stdout);
- }
- #endif
- }
-
- /*
- * Add article to arts[]
- */
- if (top >= max_art)
- expand_art();
-
- arts[top].artnum = art;
- arts[top].thread = -1;
- arts[top].inthread = FALSE;
- arts[top].unread = 1;
-
- sprintf(buf, "%s/%s/%ld", SPOOLDIR, group, art);
- fd = open(buf, 0);
- if (fd < 0) {
- fprintf(stderr, "can't open article %s: ", buf);
- perror("");
- continue;
- }
-
- if (!parse_headers(fd, &arts[top]))
- continue;
- top++;
- close(fd);
-
- if (++count % 10 == 0 && !update) {
- printf("\b\b\b\b%4d", count);
- fflush(stdout);
- }
- }
-
- return modified;
- }
-
-
- /*
- * Go through the articles in arts[] and use .thread to snake threads
- * through them. Use the subject line to construct threads. The
- * first article in a thread should have .inthread set to FALSE, the
- * rest TRUE. Only do unexprired articles we haven't visited yet
- * (arts[].thread == -1).
- */
-
- make_threads() {
- int i;
- int j;
-
- for (i = 0; i < top; i++) {
- if (arts[i].thread == -1)
- for (j = i+1; j < top; j++)
- if (arts[i].hash == arts[j].hash
- && arts[j].thread != -2
- && strncmp(arts[i].nore, arts[j].nore, 10) == 0) {
- arts[i].thread = j;
- arts[j].inthread = TRUE;
- break;
- }
- }
- }
-
-
- /*
- * Return a pointer into s eliminating any leading Re:'s. Example:
- *
- * Re: Reorganization of misc.jobs
- * ^ ^
- */
-
- char *
- eat_re(s)
- char *s;
- {
-
- #if 1
- while (*s == 'r' || *s == 'R') {
- if ((*(s+1) == 'e' || *(s+1) == 'E') && *(s+2) == ':')
- s += 3;
- else
- break;
- if (*s == ' ')
- s++;
- }
- #else
- while (*s == 'R') {
- if (strncmp(s, "Re: ", 4) == 0)
- s += 4;
- else if (strncmp(s, "Re:", 3) == 0)
- s += 3;
- else if (strncmp(s, "Re^2: ", 6) == 0)
- s += 6;
- else
- break;
- }
- #endif
-
- return s;
- }
-
-
- /*
- * Hash the subjects (after eating the Re's off) for a quicker
- * thread search later. We store the hashes for subjects in the
- * index file for speed.
- */
-
- long
- hash_s(s)
- char *s;
- {
- long h = 0;
-
- while (*s)
- h = h * 64 + *s++;
-
- return h;
- }
-
-
- parse_headers(fd, h)
- int fd;
- struct header *h;
- {
- char buf[1024];
- char *p, *q;
- char flag;
-
- if (read(fd, buf, 1024) <= 0)
- return FALSE;
-
- buf[1023] = '\0';
-
- p = buf;
-
- h->from[0] = '\0';
- h->subject[0] = '\0';
- h->nore = h->subject;
- h->hash = 0;
-
- while (1) {
- q = p;
- while (*p && *p != '\n') {
- if (*p & 0x7F < 32)
- *p = ' ';
- p++;
- }
- flag = *p;
- *p++ = '\0';
-
- if (strncmp(q, "From: ", 6) == 0) {
- strncpy(h->from, &q[6], MAX_FROM);
- h->from[MAX_FROM-1] = '\0';
- } else if (strncmp(q, "Subject: ", 9) == 0) {
- h->hash = hash_s(eat_re(&q[9]));
- strncpy(h->subject, &q[9], MAX_SUBJ);
- h->subject[MAX_SUBJ-1] = '\0';
- h->nore = eat_re(h->subject);
- }
-
- if (!flag)
- break;
- }
-
- return TRUE;
- }
-
-
- /*
- * Write out a .tindex file. Write the group name first so if
- * local indexing is done we can disambiguate between group name
- * hash collisions by looking at the index file.
- */
-
- dump_index(group)
- char *group;
- {
- int i;
- char buf[200];
- FILE *fp;
- char *p, *q;
- long l;
-
- fp = fopen(index_file, "w");
- if (fp == NULL)
- return;
-
- fprintf(fp, "%s\n", group);
- fprintf(fp, "%d\n", num_arts());
- for (i = 0; i < top; i++)
- if (arts[i].thread != -2) {
- p = arts[i].nore;
- q = arts[i].subject;
- l = p - q;
- fprintf(fp, "%ld\n%s\n%s\n%ld\n%ld\n",
- arts[i].artnum,
- arts[i].subject,
- arts[i].from,
- arts[i].hash,
- #if 0
- (long) arts[i].nore - (long) arts[i].subject);
- #else
- l);
- #endif
- }
-
- fclose(fp);
- chmod(index_file, 0644);
- }
-
-
- /*
- * strncpy that stops at a newline and null terminates
- */
-
- my_strncpy(p, q, n)
- char *p;
- char *q;
- int n;
- {
-
- while (n--) {
- if (!*q || *q == '\n')
- break;
- *p++ = *q++;
- }
- *p = '\0';
- }
-
-
- /*
- * Read in a .tindex file.
- */
-
- load_index()
- {
- int i;
- long j;
- char buf[200];
- FILE *fp;
- int first = TRUE;
-
- top = 0;
-
- fp = fopen(index_file, "r");
- if (fp == NULL)
- return;
-
- if (fgets(buf, 200, fp) == NULL
- || fgets(buf, 200, fp) == NULL) {
- fprintf(stderr, "one\n");
- goto corrupt_index;
- }
-
- i = atol(buf);
- while (top < i) {
- if (top >= max_art)
- expand_art();
-
- arts[top].thread = -2;
- arts[top].inthread = FALSE;
-
- if (fgets(buf, 200, fp) == NULL) {
- fprintf(stderr, "two\n");
- goto corrupt_index;
- }
- arts[top].artnum = atol(buf);
-
- if (fgets(buf, 200, fp) == NULL) {
- fprintf(stderr, "three\n");
- goto corrupt_index;
- }
-
- my_strncpy(arts[top].subject, buf, MAX_SUBJ-1);
-
- if (fgets(buf, 200, fp) == NULL) {
- fprintf(stderr, "four\n");
- goto corrupt_index;
- }
- my_strncpy(arts[top].from, buf, MAX_FROM-1);
-
- if (fgets(buf, 200, fp) == NULL) {
- fprintf(stderr, "five\n");
- goto corrupt_index;
- }
- arts[top].hash = atol(buf);
-
- if (fgets(buf, 200, fp) == NULL) {
- fprintf(stderr, "six\n");
- goto corrupt_index;
- }
-
- j = atol(buf);
- #if 0
- if (j < 0 || j > 100) {
- #if 0
- goto corrupt_index;
- #else
- arts[top].nore = eat_re(arts[top].subject);
- #endif
- } else
- arts[top].nore = arts[top].subject + j;
- #else
- arts[top].nore = eat_re(arts[top].subject);
- #endif
-
- top++;
- }
-
- fclose(fp);
- return;
-
- corrupt_index:
- fprintf(stderr, "index file %s corrupt\n", index_file);
- fprintf(stderr, "top = %d\n", top);
- exit(1);
- unlink(index_file);
- top = 0;
- }
-
-
- /*
- * Look in the local $HOME/.tindex (or wherever) directory for the
- * index file for the given group. Hashing the group name gets
- * a number. See if that #.1 file exists; if so, read first line.
- * Group we want? If no, try #.2. Repeat until no such file or
- * we find an existing file that matches our group.
- */
-
- find_local_index(group)
- char *group;
- {
- unsigned long h;
- static char buf[200];
- int i;
- char *p;
- FILE *fp;
-
- {
- char *t = group;
-
- h = *t++;
- while (*t)
- h = h * 64 + *t++;
- }
-
- i = 1;
- while (1) {
- sprintf(index_file, "%s/%lu.%d", indexdir, h, i);
- fp = fopen(index_file, "r");
- if (fp == NULL)
- return;
-
- if (fgets(buf, 200, fp) == NULL) {
- fclose(fp);
- return;
- }
- fclose(fp);
-
- for (p = buf; *p && *p != '\n'; p++) ;
- *p = '\0';
-
- if (strcmp(buf, group) == 0)
- return;
-
- i++;
- }
- }
-
-
- /*
- * Run the index file updater only for the groups we've loaded.
- */
-
- do_update() {
- int i;
- char group_path[200];
- char *p;
-
- for (i = 0; i < local_top; i++) {
- strcpy(group_path, active[my_group[i]].name);
- for (p = group_path; *p; p++)
- if (*p == '.')
- *p = '/';
-
- index_group(active[my_group[i]].name, group_path);
- }
- }
-
- @EOF
-
- chmod 644 art.c
-
- echo x - curses.c
- cat >curses.c <<'@EOF'
-
- /*
- * This is a screen management library borrowed with permission from the
- * Elm mail system (a great mailer--I highly recommend it!).
- *
- * I've hacked this library to only provide what Tass needs.
- *
- * Original copyright follows:
- */
-
- /*******************************************************************************
- * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
- *
- * Copyright (c) 1986 Dave Taylor
- ******************************************************************************/
-
- #include <stdio.h>
- #include <curses.h>
-
- #define TRUE 1
- #define FALSE 0
-
- #define BACKSPACE '\b'
- #define VERY_LONG_STRING 2500
-
- int LINES=23;
- int COLS=80;
-
- int inverse_okay = TRUE;
-
- /*
- #ifdef BSD
- # ifndef BSD4_1
- # include <sgtty.h>
- # else
- # include <termio.h>
- # endif
- # else
- # include <termio.h>
- #endif
- */
-
- #include <ctype.h>
-
- /*
- #ifdef BSD
- #undef tolower
- #endif
- */
-
- #define TTYIN 0
-
- #ifdef SHORTNAMES
- # define _clearinverse _clrinv
- # define _cleartoeoln _clrtoeoln
- # define _cleartoeos _clr2eos
- #endif
-
- #ifndef BSD
- struct termio _raw_tty,
- _original_tty;
- #else
- #define TCGETA TIOCGETP
- #define TCSETAW TIOCSETP
-
- struct sgttyb _raw_tty,
- _original_tty;
- #endif
-
- static int _inraw = 0; /* are we IN rawmode? */
-
- #define DEFAULT_LINES_ON_TERMINAL 24
- #define DEFAULT_COLUMNS_ON_TERMINAL 80
-
- static int _memory_locked = 0; /* are we IN memlock?? */
-
- static int _intransmit; /* are we transmitting keys? */
-
- static
- char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
- *_setinverse, *_clearinverse, *_setunderline, *_clearunderline;
-
- static
- int _lines,_columns;
-
- static char _terminal[1024]; /* Storage for terminal entry */
- static char _capabilities[1024]; /* String for cursor motion */
-
- static char *ptr = _capabilities; /* for buffering */
-
- int outchar(); /* char output for tputs */
- char *tgetstr(), /* Get termcap capability */
- *tgoto(); /* and the goto stuff */
-
- InitScreen()
- {
- int tgetent(), /* get termcap entry */
- err;
- char termname[40];
- char *strcpy(), *getenv();
-
- if (getenv("TERM") == NULL) {
- fprintf(stderr,
- "TERM variable not set; Tass requires screen capabilities\n");
- return(FALSE);
- }
- if (strcpy(termname, getenv("TERM")) == NULL) {
- fprintf(stderr,"Can't get TERM variable\n");
- return(FALSE);
- }
- if ((err = tgetent(_terminal, termname)) != 1) {
- fprintf(stderr,"Can't get entry for TERM\n");
- return(FALSE);
- }
-
- /* load in all those pesky values */
- _clearscreen = tgetstr("cl", &ptr);
- _moveto = tgetstr("cm", &ptr);
- _cleartoeoln = tgetstr("ce", &ptr);
- _cleartoeos = tgetstr("cd", &ptr);
- _lines = tgetnum("li");
- _columns = tgetnum("co");
- _setinverse = tgetstr("so", &ptr);
- _clearinverse = tgetstr("se", &ptr);
- _setunderline = tgetstr("us", &ptr);
- _clearunderline = tgetstr("ue", &ptr);
-
- if (!_clearscreen) {
- fprintf(stderr,
- "Terminal must have clearscreen (cl) capability\n");
- return(FALSE);
- }
- if (!_moveto) {
- fprintf(stderr,
- "Terminal must have cursor motion (cm)\n");
- return(FALSE);
- }
- if (!_cleartoeoln) {
- fprintf(stderr,
- "Terminal must have clear to end-of-line (ce)\n");
- return(FALSE);
- }
- if (!_cleartoeos) {
- fprintf(stderr,
- "Terminal must have clear to end-of-screen (cd)\n");
- return(FALSE);
- }
- if (_lines == -1)
- _lines = DEFAULT_LINES_ON_TERMINAL;
- if (_columns == -1)
- _columns = DEFAULT_COLUMNS_ON_TERMINAL;
- return(TRUE);
- }
-
- ScreenSize(lines, columns)
- int *lines, *columns;
- {
- /** returns the number of lines and columns on the display. **/
-
- if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
- if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
-
- *lines = _lines - 1; /* assume index from zero*/
- *columns = _columns; /* assume index from one */
- }
-
- ClearScreen()
- {
- /* clear the screen: returns -1 if not capable */
-
- tputs(_clearscreen, 1, outchar);
- fflush(stdout); /* clear the output buffer */
- }
-
- MoveCursor(row, col)
- int row, col;
- {
- /** move cursor to the specified row column on the screen.
- 0,0 is the top left! **/
-
- char *stuff, *tgoto();
-
- stuff = tgoto(_moveto, col, row);
- tputs(stuff, 1, outchar);
- fflush(stdout);
- }
-
- CleartoEOLN()
- {
- /** clear to end of line **/
-
- tputs(_cleartoeoln, 1, outchar);
- fflush(stdout); /* clear the output buffer */
- }
-
- CleartoEOS()
- {
- /** clear to end of screen **/
-
- tputs(_cleartoeos, 1, outchar);
- fflush(stdout); /* clear the output buffer */
- }
-
- StartInverse()
- {
- /** set inverse video mode **/
-
- if (_setinverse && inverse_okay)
- tputs(_setinverse, 1, outchar);
- /* fflush(stdout); */
- }
-
-
- EndInverse()
- {
- /** compliment of startinverse **/
-
- if (_clearinverse && inverse_okay)
- tputs(_clearinverse, 1, outchar);
- /* fflush(stdout); */
- }
-
- #if 0
- StartUnderline()
- {
- /** start underline mode **/
-
- if (!_setunderline)
- return(-1);
-
- tputs(_setunderline, 1, outchar);
- fflush(stdout);
- return(0);
- }
-
-
- EndUnderline()
- {
- /** the compliment of start underline mode **/
-
- if (!_clearunderline)
- return(-1);
-
- tputs(_clearunderline, 1, outchar);
- fflush(stdout);
- return(0);
- }
- #endif
-
- RawState()
- {
- /** returns either 1 or 0, for ON or OFF **/
-
- return( _inraw );
- }
-
- Raw(state)
- int state;
- {
- /** state is either TRUE or FALSE, as indicated by call **/
-
- if (state == FALSE && _inraw) {
- (void) ioctl(TTYIN, TCSETAW, &_original_tty);
- _inraw = 0;
- }
- else if (state == TRUE && ! _inraw) {
-
- (void) ioctl(TTYIN, TCGETA, &_original_tty); /** current setting **/
-
- (void) ioctl(TTYIN, TCGETA, &_raw_tty); /** again! **/
- #ifdef BSD
- _raw_tty.sg_flags &= ~(ECHO | CRMOD); /* echo off */
- _raw_tty.sg_flags |= CBREAK; /* raw on */
- #else
- _raw_tty.c_lflag &= ~(ICANON | ECHO); /* noecho raw mode */
-
- _raw_tty.c_cc[VMIN] = '\01'; /* minimum # of chars to queue */
- _raw_tty.c_cc[VTIME] = '\0'; /* minimum time to wait for input */
-
- #endif
- (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
-
- _inraw = 1;
- }
- }
-
- int
- ReadCh()
- {
- /** read a character with Raw mode set! **/
-
- register int result;
- char ch;
- result = read(0, &ch, 1);
- return((result <= 0 ) ? EOF : ch & 0x7F);
- }
-
-
- outchar(c)
- char c;
- {
- /** output the given character. From tputs... **/
- /** Note: this CANNOT be a macro! **/
-
- putc(c, stdout);
- }
-
- @EOF
-
- chmod 644 curses.c
-
- echo x - group.c
- cat >group.c <<'@EOF'
-
-
- #include <stdio.h>
- #include <signal.h>
- #include "tass.h"
-
-
- int index_point;
- int first_subj_on_screen;
- int last_subj_on_screen;
- char subject_search_string[LEN+1]; /* last search pattern */
- extern int cur_groupnum;
- extern int last_resp; /* page.c */
- extern int this_resp; /* page.c */
- extern int space_mode; /* select.c */
- extern char *cvers;
-
- char *glob_group;
-
-
- #ifdef SIGTSTP
- void
- group_susp(i)
- int i;
- {
-
- Raw(FALSE);
- putchar('\n');
- signal(SIGTSTP, SIG_DFL);
- kill(0, SIGTSTP);
-
- signal(SIGTSTP, group_susp);
- Raw(TRUE);
- mail_setup();
- show_group_page(glob_group);
- }
- #endif
-
-
- group_page(group)
- char *group;
- {
- char ch;
- int i, n;
- char group_path[200];
- char *p;
- char buf[200];
-
- glob_group = group;
-
- strcpy(group_path, group); /* turn comp.unix.amiga into */
- for (p = group_path; *p; p++) /* comp/unix/amiga */
- if (*p == '.')
- *p = '/';
-
- last_resp = -1;
- this_resp = -1;
- index_group(group, group_path); /* update index file */
- read_newsrc_line(group); /* get sequencer information */
-
- if (space_mode) {
- for (i = 0; i < top_base; i++)
- if (new_responses(i))
- break;
- if (i < top_base)
- index_point = i;
- else
- index_point = top_base - 1;
- } else
- index_point = top_base - 1;
-
- show_group_page(group);
-
- while (1) {
- ch = ReadCh();
-
- if (ch > '0' && ch <= '9') { /* 0 goes to basenote */
- prompt_subject_num(ch, group);
- } else switch (ch) {
- case 'I': /* toggle inverse video */
- inverse_okay = !inverse_okay;
- if (inverse_okay)
- info_message("Inverse video enabled");
- else
- info_message("Inverse video disabled");
- break;
-
- case 's': /* subscribe to this group */
- subscribe(group, ':', my_group[cur_groupnum],
- TRUE);
- sprintf(buf, "subscribed to %s", group);
- info_message(buf);
- break;
-
- case 'u': /* unsubscribe to this group */
- subscribe(group, '!', my_group[cur_groupnum],
- TRUE);
- sprintf(buf, "unsubscribed to %s", group);
- info_message(buf);
- break;
-
- case 'g': /* choose a new group by name */
- n = choose_new_group();
- if (n >= 0 && n != cur_groupnum) {
- fix_new_highest(cur_groupnum);
- cur_groupnum = n;
- index_point = -3;
- goto group_done;
- }
- break;
-
- case 'c': /* catchup--mark all articles as read */
- if (prompt_yn("Mark everything as read? (y/n): ")) {
- for (n = 0; n < top; n++)
- arts[n].unread = 0;
- show_group_page(group);
- info_message("All articles marked as read");
- }
- break;
-
- case 27: /* common arrow keys */
- ch = ReadCh();
- if (ch == '[' || ch == 'O')
- ch = ReadCh();
- switch (ch) {
- case 'A':
- case 'D':
- case 'i':
- goto group_up;
-
- case 'B':
- case 'I':
- case 'C':
- goto group_down;
- }
- break;
-
- case 'n': /* next group */
- clear_message();
- if (cur_groupnum + 1 >= local_top)
- info_message("No more groups");
- else {
- fix_new_highest(cur_groupnum);
- cur_groupnum++;
- index_point = -3;
- space_mode = FALSE;
- goto group_done;
- }
- break;
-
- case 'p': /* previous group */
- clear_message();
- if (cur_groupnum <= 0)
- info_message("No previous group");
- else {
- fix_new_highest(cur_groupnum);
- cur_groupnum--;
- index_point = -3;
- space_mode = FALSE;
- goto group_done;
- }
- break;
-
- case ' ':
- if (top_base <= 0)
- info_message("*** No Articles ***");
- else if (last_subj_on_screen == top_base)
- info_message("*** End of Articles ***");
- else
- clear_message();
- break;
-
- case '\t':
- fix_new_highest(cur_groupnum);
- space_mode = TRUE;
-
- if (index_point < 0
- || (n=next_unread((int) base[index_point]))<0) {
- for (i = cur_groupnum+1;
- i < local_top; i++)
- if (unread[i] > 0)
- break;
- if (i >= local_top)
- goto group_done;
-
- cur_groupnum = i;
- index_point = -3;
- goto group_done;
- }
- index_point = show_page(n, group, group_path);
- if (index_point < 0)
- goto group_done;
- show_group_page(group);
- break;
-
-
- case 'N': /* go to next unread article */
- if (index_point < 0) {
- info_message("No next unread article");
- break;
- }
-
- n = next_unread( (int) base[index_point]);
- if (n == -1)
- info_message("No next unread article");
- else {
- index_point =
- show_page(n, group, group_path);
- if (index_point < 0) {
- fix_new_highest(cur_groupnum);
- space_mode = FALSE;
- goto group_done;
- }
- show_group_page(group);
- }
- break;
-
- case 'P': /* go to previous unread article */
- if (index_point < 0) {
- info_message("No previous unread article");
- break;
- }
-
- n = prev_response( (int) base[index_point]);
- n = prev_unread(n);
- if (n == -1)
- info_message("No previous unread article");
- else {
- index_point =
- show_page(n, group, group_path);
- if (index_point < 0) {
- fix_new_highest(cur_groupnum);
- space_mode = FALSE;
- goto group_done;
- }
- show_group_page(group);
- }
- break;
-
- case 'w': /* post a basenote */
- post_base(group);
- update_newsrc(group, my_group[cur_groupnum]);
- index_group(group, group_path);
- read_newsrc_line(group);
- index_point = top_base - 1;
- show_group_page(group);
- break;
-
- case 't': /* return to group selection page */
- fix_new_highest(cur_groupnum);
- goto group_done;
-
- case '\r':
- case '\n': /* read current basenote */
- if (index_point < 0) {
- info_message("*** No Articles ***");
- break;
- }
- index_point = show_page((int) base[index_point],
- group, group_path);
- if (index_point < 0) {
- fix_new_highest(cur_groupnum);
- space_mode = FALSE;
- goto group_done;
- }
- show_group_page(group);
- break;
-
- case ctrl('D'): /* page down */
- if (!top_base || index_point == top_base - 1)
- break;
-
- erase_subject_arrow();
- index_point += NOTESLINES / 2;
- if (index_point >= top_base)
- index_point = top_base - 1;
-
- if (index_point < first_subj_on_screen
- || index_point >= last_subj_on_screen)
- show_group_page(group);
- else
- draw_subject_arrow();
- break;
-
- case '-': /* go to last viewed article */
- if (this_resp < 0) {
- info_message("No last message");
- break;
- }
- index_point = show_page(this_resp,
- group, group_path);
- if (index_point < 0) {
- fix_new_highest(cur_groupnum);
- space_mode = FALSE;
- goto group_done;
- }
- show_group_page(group);
- break;
-
- case ctrl('U'): /* page up */
- if (!top_base)
- break;
-
- erase_subject_arrow();
- index_point -= NOTESLINES / 2;
- if (index_point < 0)
- index_point = 0;
- if (index_point < first_subj_on_screen
- || index_point >= last_subj_on_screen)
- show_group_page(group);
- else
- draw_subject_arrow();
- break;
-
- case 'v':
- info_message(cvers);
- break;
-
- case '!':
- shell_escape();
- show_group_page(group);
- break;
-
- case ctrl('N'):
- case 'j': /* line down */
- group_down:
- if (!top_base || index_point + 1 >= top_base)
- break;
-
- if (index_point + 1 >= last_subj_on_screen) {
- index_point++;
- show_group_page(group);
- } else {
- erase_subject_arrow();
- index_point++;
- draw_subject_arrow();
- }
- break;
-
- case ctrl('P'):
- case 'k': /* line up */
- group_up:
- if (!top_base || !index_point)
- break;
-
- if (index_point <= first_subj_on_screen) {
- index_point--;
- show_group_page(group);
- } else {
- erase_subject_arrow();
- index_point--;
- draw_subject_arrow();
- }
- break;
-
- case ctrl('R'):
- case ctrl('L'):
- case ctrl('W'):
- case 'i': /* return to index */
- show_group_page(group);
- break;
-
- case '/': /* forward search */
- search_subject(TRUE, group);
- break;
-
- case '?': /* backward search */
- search_subject(FALSE, group);
- break;
-
- case 'q': /* quit */
- index_point = -2;
- fix_new_highest(cur_groupnum);
- space_mode = FALSE;
- goto group_done;
-
- case 'h':
- tass_group_help();
- show_group_page(group);
- break;
-
- default:
- info_message("Bad command. Type 'h' for help.");
- }
- }
-
- group_done:
- update_newsrc(group, my_group[cur_groupnum]);
-
- if (index_point == -2)
- tass_done(0);
- }
-
-
- /*
- * Correct highest[] for the group selection page display since
- * new articles may have been read or marked unread
- */
-
- fix_new_highest(groupnum)
- int groupnum;
- {
- int i;
- int sum = 0;
-
- for (i = 0; i < top; i++)
- if (arts[i].unread)
- sum++;
-
- unread[groupnum] = sum;
- }
-
-
- show_group_page(group)
- char *group;
- {
- int i;
- int n;
- char resps[10];
- char new_resps;
- int respnum;
-
- #ifdef SIGTSTP
- signal(SIGTSTP, group_susp);
- #endif
-
- ClearScreen();
- printf("%s\r\n", nice_time()); /* time in upper left */
- center_line(1, group);
-
- if (mail_check()) { /* you have mail message in */
- MoveCursor(0, 66); /* upper right */
- printf("you have mail\n");
- }
-
- MoveCursor(INDEX_TOP, 0);
-
- first_subj_on_screen = (index_point / NOTESLINES) * NOTESLINES;
- if (first_subj_on_screen < 0)
- first_subj_on_screen = 0;
-
- last_subj_on_screen = first_subj_on_screen + NOTESLINES;
- if (last_subj_on_screen >= top_base) {
- last_subj_on_screen = top_base;
- first_subj_on_screen = top_base - NOTESLINES;
-
- if (first_subj_on_screen < 0)
- first_subj_on_screen = 0;
- }
-
- for (i = first_subj_on_screen; i < last_subj_on_screen; i++) {
- if (new_responses(i))
- new_resps = '+';
- else
- new_resps = ' ';
-
- n = nresp(i);
- if (n)
- sprintf(resps, "%4d", n);
- else
- strcpy(resps, " ");
-
- respnum = base[i];
-
- printf(" %4d %-*s %s %-*s %c\r\n",
- i + 1,
- MAX_SUBJ,
- arts[respnum].subject,
- resps,
- MAX_FROM,
- arts[respnum].from,
- new_resps);
- }
-
- if (top_base <= 0)
- info_message("*** No Articles ***");
- else if (last_subj_on_screen == top_base)
- info_message("*** End of Articles ***");
-
- if (top_base > 0)
- draw_subject_arrow();
- }
-
- draw_subject_arrow() {
-
- draw_arrow(INDEX_TOP + (index_point-first_subj_on_screen) );
- }
-
- erase_subject_arrow() {
-
- erase_arrow(INDEX_TOP + (index_point-first_subj_on_screen) );
- }
-
-
- prompt_subject_num(ch, group)
- char ch;
- char *group;
- {
- int num;
-
-
- clear_message();
-
- if ((num = parse_num(ch, "Read article> ")) == -1) {
- clear_message();
- return FALSE;
- }
- num--; /* index from 0 (internal) vs. 1 (user) */
-
- if (num >= top_base)
- num = top_base - 1;
-
- if (num >= first_subj_on_screen
- && num < last_subj_on_screen) {
- erase_subject_arrow();
- index_point = num;
- draw_subject_arrow();
- } else {
- index_point = num;
- show_group_page(group);
- }
- }
-
-
- search_subject(forward, group)
- int forward;
- char *group;
- {
- char buf[LEN+1];
- int i;
- extern char *regcmp();
- extern char *regex();
- char *re;
- char *prompt;
-
- clear_message();
-
- if (forward)
- prompt = "/";
- else
- prompt = "?";
-
- if (!parse_string(prompt, buf))
- return;
-
- if (strlen(buf))
- strcpy(subject_search_string, buf);
- else if (!strlen(subject_search_string)) {
- info_message("No search pattern");
- return;
- }
-
- i = index_point;
-
- glob_name(subject_search_string, buf);
-
- if ((re = regcmp(buf, NULL)) == NULL) {
- info_message("Bad search pattern");
- return;
- }
-
- do {
- if (forward)
- i++;
- else
- i--;
-
- if (i >= top_base)
- i = 0;
- if (i < 0)
- i = top_base - 1;
-
- if (regex(re, arts[ base[i] ].subject) != NULL) {
- if (i >= first_subj_on_screen
- && i < last_subj_on_screen) {
- erase_subject_arrow();
- index_point = i;
- draw_subject_arrow();
- } else {
- index_point = i;
- show_group_page(group);
- }
- return;
- }
- } while (i != index_point);
-
- info_message("No match");
- }
-
-
- /*
- * Post an original article (not a followup)
- */
-
- post_base(group)
- char *group;
- {
- FILE *fp;
- char nam[100];
- char ch;
- char subj[LEN+1];
- char buf[200];
-
- if (!parse_string("Subject: ", subj))
- return;
- if (subj[0] == '\0')
- return;
-
- setuid(real_uid);
- setgid(real_gid);
-
- sprintf(nam, "%s/.article", homedir);
- if ((fp = fopen(nam, "w")) == NULL) {
- fprintf(stderr, "can't open %s: ", nam);
- perror("");
- return(FALSE);
- }
- chmod(nam, 0600);
-
- fprintf(fp, "Subject: %s\n", subj);
- fprintf(fp, "Newsgroups: %s\n", group);
- fprintf(fp, "Distribution: \n");
- if (*my_org)
- fprintf(fp, "Organization: %s\n", my_org);
- fprintf(fp, "\n");
-
- fclose(fp);
-
- ch = 'e';
- while (1) {
- switch (ch) {
- case 'e':
- invoke_editor(nam);
- break;
-
- case 'a':
- return FALSE;
-
- case 'p':
- printf("\nPosting... ");
- fflush(stdout);
- sprintf(buf, "%s/inews -h < %s", LIBDIR, nam);
- if (invoke_cmd(buf)) {
- printf("article posted\n");
- fflush(stdout);
- goto post_base_done;
- } else {
- printf("article rejected\n");
- fflush(stdout);
- break;
- }
- }
-
- do {
- MoveCursor(LINES, 0);
- fputs("abort, edit, post: ", stdout);
- fflush(stdout);
- ch = ReadCh();
- } while (ch != 'a' && ch != 'e' && ch != 'p');
- }
-
- post_base_done:
- setuid(tass_uid);
- setgid(tass_gid);
-
- continue_prompt();
-
- return(TRUE);
- }
-
-
- /*
- * Return the number of unread articles there are within a thread
- */
-
- new_responses(thread)
- int thread;
- {
- int i;
- int sum = 0;
-
- for (i = base[thread]; i >= 0; i = arts[i].thread)
- if (arts[i].unread)
- sum++;
-
- return sum;
- }
-
-
- tass_group_help() {
- char ch;
-
- group_help_start:
-
- ClearScreen();
- center_line(0, TASS_HEADER);
- center_line(1, "Index Page Commands (page 1 of 2)");
-
- MoveCursor(3, 0);
-
- printf("4 Select article 4\r\n");
- printf("^D Page down\r\n");
- printf("^U Page up\r\n");
- printf("<CR> Read current article\r\n");
- printf("<TAB> View next unread article or group\r\n");
- printf("c Mark all articles as read\r\n");
- printf("g Choose a new group by name\r\n");
- printf("j Down a line\r\n");
- printf("k Up a line\r\n");
- printf("n Go to next group\n");
- printf("N Go to next unread article\n");
- printf("p Go to previous group\n");
- printf("P Go to previous unread article\n");
- printf("q Quit\r\n");
-
- center_line(LINES, "-- hit space for more commands --");
- ch = ReadCh();
- if (ch != ' ')
- return;
-
- ClearScreen();
- center_line(0, TASS_HEADER);
- center_line(1, "Index Page Commands (page 2 of 2)");
-
- MoveCursor(3, 0);
-
- printf("s Subscribe to this group\r\n");
- printf("t Return to group selection index\r\n");
- printf("u Unsubscribe to this group\r\n");
- printf("w Post an article\r\n");
- printf("/ Search forward for subject\r\n");
- printf("? Search backward for subject\r\n");
- printf("- Show last message\r\n");
-
- center_line(LINES, "-- hit any key --");
- ch = ReadCh();
- if (ch == 'b')
- goto group_help_start;
- }
-
- @EOF
-
- chmod 644 group.c
-
- echo x - mail.c
- cat >mail.c <<'@EOF'
-
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
- #define TRUE 1
- #define FALSE 0
-
-
- char *mailbox_name = NULL;
- off_t mailbox_size;
-
-
- /*
- * Record size of mailbox so we can detect if new mail has arrived
- */
-
- mail_setup() {
- struct stat buf;
- extern char *getenv();
-
- if (mailbox_name == NULL)
- mailbox_name = getenv("MAIL");
-
- if (mailbox_name == NULL)
- mailbox_size = 0;
- else {
- if (stat(mailbox_name, &buf) >= 0)
- mailbox_size = buf.st_size;
- else
- mailbox_size = 0;
- }
- }
-
-
- /*
- * Return TRUE if new mail has arrived
- */
-
- mail_check() {
- struct stat buf;
-
- if (mailbox_name != NULL
- && stat(mailbox_name, &buf) >= 0
- && mailbox_size < buf.st_size)
- return TRUE;
-
- return FALSE;
- }
-
- @EOF
-
- chmod 640 mail.c
-
- echo x - main.c
- cat >main.c <<'@EOF'
-
- /*
- * Tass, a visual Usenet news reader
- * (c) Copyright 1990 by Rich Skrenta
- *
- * Distribution agreement:
- *
- * You may freely copy or redistribute this software, so long
- * as there is no profit made from its use, sale, trade or
- * reproduction. You may not change this copyright notice,
- * and it must be included prominently in any copy made.
- */
-
- #include <stdio.h>
- #include <signal.h>
- #include "tass.h"
-
-
- int LINES, COLS;
-
- int max_active;
- struct group_ent *active; /* active file */
- int group_hash[TABLE_SIZE]; /* group name --> active[] */
- int *my_group; /* .newsrc --> active[] */
- int *unread; /* highest art read in group */
- int num_active; /* one past top of active */
- int local_top; /* one past top of my_group */
- int update = FALSE; /* update index files only mode */
-
- struct header *arts;
- long *base;
- int max_art;
- int top = 0;
- int top_base;
-
- int tass_uid;
- int tass_gid;
- int real_uid;
- int real_gid;
-
- int local_index; /* do private indexing? */
-
- char *cvers = "Tass 3.0 (c) Copyright 1991 by Rich Skrenta. All rights reserved";
-
-
- #ifdef SIGTSTP
- void
- main_susp(i)
- int i;
- {
-
- Raw(FALSE);
- putchar('\n');
- signal(SIGTSTP, SIG_DFL);
- kill(0, SIGTSTP);
-
- signal(SIGTSTP, main_susp);
- mail_setup();
- Raw(TRUE);
- }
- #endif
-
-
- main(argc, argv)
- int argc;
- char **argv;
- {
- extern int optind, opterr;
- extern char *optarg;
- int errflag = 0;
- int i;
- int c;
-
- for (i = 0; i < TABLE_SIZE; i++)
- group_hash[i] = -1;
-
- signal(SIGPIPE, SIG_IGN);
- #ifdef SIGTSTP
- signal(SIGTSTP, main_susp);
- #endif
-
- tass_uid = geteuid();
- tass_gid = getegid();
- real_uid = getuid();
- real_gid = getgid();
-
- init_selfinfo(); /* set up char *'s: homedir, newsrc, etc. */
- init_alloc(); /* allocate initial array sizes */
-
- if (tass_uid == real_uid) { /* run out of someone's account */
- local_index = TRUE; /* index in their home directory */
- mkdir(indexdir, 0755);
- } else /* we're setuid, index in /usr/spool/news */
- local_index = FALSE;
-
- read_active(); /* load the active file into active[] */
-
- while ((c = getopt(argc, argv, "f:u")) != -1) {
- switch(c) {
- case 'f':
- strcpy(newsrc, optarg);
- break;
-
- case 'u':
- update = TRUE;
- break;
-
- case '?':
- default:
- errflag++;
- }
- }
-
- if (errflag) {
- fprintf(stderr, "usage: tass [options] [newsgroups]\n");
- fprintf(stderr, " -f file use file instead of $HOME/.newsrc\n");
- fprintf(stderr, " -u update index files only\n");
- exit(1);
- }
-
- if (!update)
- printf("Tass 3.0\n");
-
- if (optind < argc) {
- while (optind < argc) {
- if (add_group(argv[optind], TRUE) < 0)
- fprintf(stderr,
- "group %s not found in active file\n",
- argv[optind]);
- optind++;
- }
- } else
- read_newsrc(TRUE);
-
- if (update) { /* index file updater only */
- do_update();
- exit(0);
- }
-
- if (InitScreen() == FALSE) {
- fprintf(stderr,"Screen initialization failed\n");
- exit(1);
- }
-
- ScreenSize(&LINES, &COLS);
- Raw(TRUE);
-
- mail_setup(); /* record mailbox size for "you have mail" */
- selection_index();
-
- tass_done(0);
- }
-
-
-
- tass_done(ret)
- int ret;
- {
-
- MoveCursor(LINES, 0);
- printf("\r\n");
- Raw(FALSE);
- exit(ret);
- }
-
-
- /*
- * Dynamic table management
- * These settings are memory conservative: small initial allocations
- * and a 50% expansion on table overflow. A fast vm system with
- * much memory might want to start with higher initial allocations
- * and a 100% expansion on overflow, especially for the arts[] array.
- */
-
- init_alloc() {
-
- max_active = 100; /* initial alloc */
-
- active = (struct group_ent *) my_malloc(sizeof(*active) * max_active);
- my_group = (int *) my_malloc(sizeof(int) * max_active);
- unread = (int *) my_malloc(sizeof(int) * max_active);
-
- max_art = 300; /* initial alloc */
-
- arts = (struct header *) my_malloc(sizeof(*arts) * max_art);
- base = (long *) my_malloc(sizeof(long) * max_art);
- }
-
-
- expand_art() {
-
- max_art += max_art / 2; /* increase by 50% */
-
- arts = (struct header *) my_realloc(arts, sizeof(*arts) * max_art);
- base = (long *) my_realloc(base, sizeof(long) * max_art);
- }
-
-
- expand_active() {
-
- max_active += max_active / 2; /* increase by 50% */
-
- active = (struct group_ent *) my_realloc(active,
- sizeof(*active) * max_active);
- my_group = (int *) my_realloc(my_group, sizeof(int) * max_active);
- unread = (int *) my_realloc(unread, sizeof(int) * max_active);
- }
-
-
- /*
- * Load the active file into active[]
- */
-
- read_active()
- {
- FILE *fp;
- char *p, *q;
- char buf[200];
- long h;
- int i;
-
- num_active = 0;
-
- if ((fp = fopen(active_file, "r")) == NULL) {
- fprintf(stderr, "can't open %s: ", active_file);
- perror("");
- exit(1);
- }
-
- while (fgets(buf, 200, fp) != NULL) {
- for (p = buf; *p && *p != ' '; p++) ;
- if (*p != ' ') {
- fprintf(stderr, "active file corrupt\n");
- continue;
- }
- *p++ = '\0';
-
- if (num_active >= max_active)
- expand_active();
-
- { /* hash group name for fast lookup later */
- char *t = buf;
-
- h = *t++;
- while (*t)
- h = (h * 64 + *t++) % TABLE_SIZE;
- }
-
- if (group_hash[h] == -1)
- group_hash[h] = num_active;
- else { /* hash linked list chaining */
- for (i = group_hash[h]; active[i].next >= 0;
- i = active[i].next) {
- if (strcmp(active[i].name, buf) == 0)
- goto read_active_continue;
- /* kill dups */
- }
- if (strcmp(active[i].name, buf) == 0)
- goto read_active_continue;
- active[i].next = num_active;
- }
-
- for (q = p; *q && *q != ' '; q++) ;
- if (*q != ' ') {
- fprintf(stderr, "active file corrupt\n");
- continue;
- }
-
- active[num_active].name = str_save(buf);
- active[num_active].max = atol(p);
- active[num_active].min = atol(q);
- active[num_active].next = -1; /* hash chaining */
- active[num_active].flag = NOTGOT; /* not in my_group[] yet */
-
- num_active++;
-
- read_active_continue:;
-
- }
-
- fclose(fp);
- }
-
-
-
- /*
- * Read $HOME/.newsrc into my_group[]. my_group[] ints point to
- * active[] entries. Sub_only determines whether we just read
- * subscribed groups or all of them.
- */
-
- read_newsrc(sub_only)
- int sub_only; /* TRUE=subscribed groups only, FALSE=all groups */
- {
- FILE *fp;
- char *p;
- char buf[8192];
- char c;
- int i;
-
- local_top = 0;
-
- fp = fopen(newsrc, "r");
- if (fp == NULL) { /* attempt to make a .newsrc */
- for (i = 0; i < num_active; i++) {
- if (local_top >= max_active)
- expand_active();
- my_group[local_top] = i;
- active[i].flag = 0;
- #if 0
- unread[local_top] = active[i].max - active[i].min;
- #else
- unread[local_top] = -1;
- #endif
- local_top++;
- }
- write_newsrc();
- return;
- }
-
- while (fgets(buf, 8192, fp) != NULL) {
- p = buf;
- while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- *p++ = '\0';
- if (c == '!' && sub_only)
- continue; /* unsubscribed */
-
- if ((i = add_group(buf, FALSE)) < 0) {
- fprintf(stderr, "group %s not found in active file\n", buf);
- continue;
- }
-
- if (c != '!') /* if we're subscribed to it */
- active[my_group[i]].flag |= SUBS;
-
- unread[i] = parse_unread(p, my_group[i]);
- }
- fclose(fp);
- }
-
-
- /*
- * Write a new newsrc from my_group[] and active[]
- * Used to a create a new .newsrc if there isn't one already, or when
- * the newsrc is reset.
- */
-
- write_newsrc() {
- FILE *fp;
- int i;
-
- setuid(real_uid); /* become the user to write in his */
- setgid(real_gid); /* home directory */
-
- fp = fopen(newsrc, "w");
- if (fp == NULL)
- goto write_newsrc_done;
-
- for (i = 0; i < num_active; i++)
- fprintf(fp, "%s: \n", active[i].name);
-
- fclose(fp);
-
- write_newsrc_done:
- setuid(tass_uid);
- setgid(tass_gid);
- }
-
-
- /*
- * Load the sequencer rang lists and mark arts[] according to the
- * .newsrc info for a particular group. i.e. rec.arts.comics: 1-94,97
- */
-
- read_newsrc_line(group)
- char *group;
- {
- FILE *fp;
- char buf[8192];
- char *p;
-
- fp = fopen(newsrc, "r");
- if (fp == NULL)
- return;
-
- while (fgets(buf, 8192, fp) != NULL) {
- p = buf;
- while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
- p++;
- *p++ = '\0';
- if (strcmp(buf, group) != 0)
- continue;
- parse_seq(p);
- break;
- }
-
- fclose(fp);
- }
-
-
- /*
- * For our current group, update the sequencer information in .newsrc
- */
-
- update_newsrc(group, groupnum)
- char *group;
- int groupnum; /* index into active[] for this group */
- {
- FILE *fp;
- FILE *newfp;
- char buf[8192];
- char *p;
- char c;
- int gotit = FALSE;
-
- setuid(real_uid);
- setgid(real_gid);
-
- fp = fopen(newsrc, "r");
- newfp = fopen(newnewsrc, "w");
- if (newfp == NULL)
- goto update_done;
-
- if (fp != NULL) {
- while (fgets(buf, 8192, fp) != NULL) {
- for (p = buf; *p; p++)
- if (*p == '\n') {
- *p = '\0';
- break;
- }
-
- p = buf;
- while (*p && *p != ' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- if (c != '\0')
- *p++ = '\0';
-
- if (c != '!')
- c = ':';
-
- if (strcmp(buf, group) == 0) {
- fprintf(newfp, "%s%c ", buf, c);
- gotit = TRUE;
- print_seq(newfp, groupnum);
- fprintf(newfp, "\n");
- } else
- fprintf(newfp, "%s%c%s\n", buf, c, p);
- }
- fclose(fp);
- }
-
- fclose(newfp);
- unlink(newsrc);
- link(newnewsrc, newsrc);
- unlink(newnewsrc);
-
- update_done:
- setuid(tass_uid);
- setgid(tass_gid);
- }
-
-
- /*
- * Subscribe/unsubscribe to a group in .newsrc. ch should either be
- * '!' to unsubscribe or ':' to subscribe. num is the group's index
- * in active[].
- */
-
- subscribe(group, ch, num, out_seq)
- char *group;
- char ch;
- int num;
- int out_seq; /* output sequencer info? */
- {
- FILE *fp;
- FILE *newfp;
- char buf[8192];
- char *p;
- char c;
- int gotit = FALSE;
-
- if (ch == '!')
- active[num].flag &= ~SUBS;
- else
- active[num].flag |= SUBS;
-
- setuid(real_uid);
- setgid(real_gid);
-
- fp = fopen(newsrc, "r");
- newfp = fopen(newnewsrc, "w");
- if (newfp == NULL)
- goto update_done;
-
- if (fp != NULL) {
- while (fgets(buf, 8192, fp) != NULL) {
- for (p = buf; *p; p++)
- if (*p == '\n') {
- *p = '\0';
- break;
- }
-
- p = buf;
- while (*p && *p != ' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- if (c != '\0')
- *p++ = '\0';
-
- if (c != '!')
- c = ':';
-
- if (strcmp(buf, group) == 0) {
- fprintf(newfp, "%s%c%s\n", buf, ch, p);
- gotit = TRUE;
- } else
- fprintf(newfp, "%s%c%s\n", buf, c, p);
- }
- fclose(fp);
- }
-
- if (!gotit) {
- if (out_seq) {
- fprintf(newfp, "%s%c ", group, ch);
- print_seq(newfp, num);
- fprintf(newfp, "\n");
- } else
- fprintf(newfp, "%s%c\n", group, ch);
- }
-
- fclose(newfp);
- unlink(newsrc);
- link(newnewsrc, newsrc);
- unlink(newnewsrc);
-
- update_done:
- setuid(tass_uid);
- setgid(tass_gid);
- }
-
-
- print_seq(fp, groupnum)
- FILE *fp;
- int groupnum; /* index into active[] for this group */
- {
- int i;
- int flag = FALSE;
-
- if (top <= 0) {
- if (active[groupnum].min > 1) {
- fprintf(fp, "1-%ld", active[groupnum].min);
- fflush(fp);
- }
- return;
- }
-
- i = 0;
- if (arts[0].artnum > 1) {
- for (; i < top && !arts[i].unread; i++) ;
- if (i > 0)
- fprintf(fp, "1-%ld", arts[i-1].artnum);
- else
- fprintf(fp, "1-%ld", arts[0].artnum - 1);
- flag = TRUE;
- }
-
- for (; i < top; i++) {
- if (!arts[i].unread) {
- if (flag)
- fprintf(fp, ",");
- else
- flag = TRUE;
- fprintf(fp, "%ld", arts[i].artnum);
- if (i+1 < top && !arts[i+1].unread) {
- while (i+1 < top && !arts[i+1].unread)
- i++;
- fprintf(fp, "-%ld", arts[i].artnum);
- }
- }
- }
-
- if (!flag && active[groupnum].min > 1)
- fprintf(fp, "1-%ld", active[groupnum].min);
- fflush(fp);
- }
-
-
- parse_seq(s)
- char *s;
- {
- long low, high;
- int i;
-
- while (*s) {
- while (*s && (*s < '0' || *s > '9'))
- s++;
-
- if (*s && *s >= '0' && *s <= '9') {
- low = atol(s);
- while (*s && *s >= '0' && *s <= '9')
- s++;
- if (*s == '-') {
- s++;
- high = atol(s);
- while (*s && *s >= '0' && *s <= '9')
- s++;
- } else
- high = low;
-
- for (i = 0; i < top; i++)
- if (arts[i].artnum >= low &&
- arts[i].artnum <= high)
- arts[i].unread = 0;
- }
- }
- }
-
-
- parse_unread(s, groupnum)
- char *s;
- int groupnum; /* index for group in active[] */
- {
- long low, high;
- long last_high;
- int i;
- int sum = 0;
- int gotone = FALSE;
- int n;
-
- /*
- * Read the first range from the .newsrc sequencer information. If the
- * top of the first range is higher than what the active file claims is
- * the bottom, use it as the new bottom instead
- */
-
- high = 0;
- if (*s) {
- while (*s && (*s < '0' || *s > '9'))
- s++;
-
- if (*s && *s >= '0' && *s <= '9') {
- low = atol(s);
- while (*s && *s >= '0' && *s <= '9')
- s++;
- if (*s == '-') {
- s++;
- high = atol(s);
- while (*s && *s >= '0' && *s <= '9')
- s++;
- } else
- high = low;
- gotone = TRUE;
- }
- }
-
- if (high < active[groupnum].min)
- high = active[groupnum].min;
-
- while (*s) {
- last_high = high;
-
- while (*s && (*s < '0' || *s > '9'))
- s++;
-
- if (*s && *s >= '0' && *s <= '9') {
- low = atol(s);
- while (*s && *s >= '0' && *s <= '9')
- s++;
- if (*s == '-') {
- s++;
- high = atol(s);
- while (*s && *s >= '0' && *s <= '9')
- s++;
- } else
- high = low;
-
- if (low > last_high) /* otherwise seq out of order */
- sum += (low - last_high) - 1;
- }
- }
-
- if (gotone) {
- if (active[groupnum].max > high)
- sum += active[groupnum].max - high;
- return sum;
- }
-
- n = (int) (active[groupnum].max - active[groupnum].min);
- if (n < 2)
- return 0;
-
- return -1;
- }
-
-
- get_line_unread(group, groupnum)
- char *group;
- int groupnum; /* index for group in active[] */
- {
- FILE *fp;
- char buf[8192];
- char *p;
- int ret = -1;
-
- fp = fopen(newsrc, "r");
- if (fp == NULL)
- return -1;
-
- while (fgets(buf, 8192, fp) != NULL) {
- p = buf;
- while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
- p++;
- *p++ = '\0';
- if (strcmp(buf, group) != 0)
- continue;
- ret = parse_unread(p, groupnum);
- break;
- }
-
- fclose(fp);
- return ret;
- }
-
-
- reset_newsrc()
- {
- FILE *fp;
- FILE *newfp;
- char buf[8192];
- char *p;
- char c;
- int gotit = FALSE;
- int i;
-
- setuid(real_uid);
- setgid(real_gid);
-
- fp = fopen(newsrc, "r");
- newfp = fopen(newnewsrc, "w");
- if (newfp == NULL)
- goto update_done;
-
- if (fp != NULL) {
- while (fgets(buf, 8192, fp) != NULL) {
- for (p = buf; *p && *p != '\n'; p++) ;
- *p = '\0';
-
- p = buf;
- while (*p && *p != ' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- if (c != '\0')
- *p++ = '\0';
-
- if (c != '!')
- c = ':';
-
- fprintf(newfp, "%s%c\n", buf, c);
- }
- fclose(fp);
- }
-
- fclose(newfp);
- unlink(newsrc);
- link(newnewsrc, newsrc);
- unlink(newnewsrc);
-
- update_done:
- setuid(tass_uid);
- setgid(tass_gid);
-
- for (i = 0; i < local_top; i++)
- unread[i] = -1;
- }
-
-
- delete_group(group)
- char *group;
- {
- FILE *fp;
- FILE *newfp;
- char buf[8192];
- char *p;
- char c;
- int gotit = FALSE;
- FILE *del;
-
- setuid(real_uid);
- setgid(real_gid);
-
- fp = fopen(newsrc, "r");
- newfp = fopen(newnewsrc, "w");
- if (newfp == NULL)
- goto del_done;
- del = fopen(delgroups, "a+");
- if (del == NULL)
- goto del_done;
-
- if (fp != NULL) {
- while (fgets(buf, 8192, fp) != NULL) {
- for (p = buf; *p && *p != '\n'; p++) ;
- *p = '\0';
-
- p = buf;
- while (*p && *p != ' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- if (c != '\0')
- *p++ = '\0';
-
- if (c != '!')
- c = ':';
-
- if (strcmp(buf, group) == 0) {
- fprintf(del, "%s%c%s\n", buf, c, p);
- gotit = TRUE;
- } else
- fprintf(newfp, "%s%c%s\n", buf, c, p);
- }
- fclose(fp);
- }
-
- fclose(newfp);
-
- if (!gotit)
- fprintf(del, "%s! \n", group);
-
- fclose(del);
- unlink(newsrc);
- link(newnewsrc, newsrc);
- unlink(newnewsrc);
-
- del_done:
- setuid(tass_uid);
- setgid(tass_gid);
- }
-
-
- undel_group() {
- FILE *del;
- FILE *newfp;
- FILE *fp;
- char buf[2][8192];
- char *p;
- int which = 0;
- long h;
- extern int cur_groupnum;
- int i, j;
- char c;
-
- setuid(real_uid);
- setgid(real_gid);
-
- del = fopen(delgroups, "r");
- if (del == NULL) {
- setuid(tass_uid);
- setgid(tass_gid);
- return FALSE;
- }
- unlink(delgroups);
- newfp = fopen(delgroups, "w");
- if (newfp == NULL) {
- setuid(tass_uid);
- setgid(tass_gid);
- return FALSE;
- }
-
- buf[0][0] = '\0';
- buf[1][0] = '\0';
-
- while (fgets(buf[which], 8192, del) != NULL) {
- which = !which;
- if (*buf[which])
- fputs(buf[which], newfp);
- }
-
- fclose(del);
- fclose(newfp);
- which = !which;
-
- if (!*buf[which]) {
- setuid(tass_uid);
- setgid(tass_gid);
- return FALSE;
- }
-
- for (p = buf[which]; *p && *p != '\n'; p++) ;
- *p = '\0';
-
- p = buf[which];
- while (*p && *p != ' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- if (c != '\0')
- *p++ = '\0';
-
- if (c != '!')
- c = ':';
-
- { /* find the hash of the group name */
- char *t = buf[which];
-
- h = *t++;
- while (*t)
- h = (h * 64 + *t++) % TABLE_SIZE;
- }
-
- for (i = group_hash[h]; i >= 0; i = active[i].next) {
- if (strcmp(buf[which], active[i].name) == 0) {
- for (j = 0; j < local_top; j++)
- if (my_group[j] == i) {
- setuid(tass_uid);
- setgid(tass_gid);
- return j;
- }
-
- active[i].flag &= ~NOTGOT; /* mark that we got it */
- if (c != '!')
- active[i].flag |= SUBS;
-
- if (local_top >= max_active)
- expand_active();
- local_top++;
- for (j = local_top; j > cur_groupnum; j--) {
- my_group[j] = my_group[j-1];
- unread[j] = unread[j-1];
- }
- my_group[cur_groupnum] = i;
- unread[cur_groupnum] = parse_unread(p, i);
-
- fp = fopen(newsrc, "r");
- if (fp == NULL) {
- setuid(tass_uid);
- setgid(tass_gid);
- return FALSE;
- }
- newfp = fopen(newnewsrc, "w");
- if (newfp == NULL) {
- fclose(fp);
- setuid(tass_uid);
- setgid(tass_gid);
- return FALSE;
- }
- i = 0;
- while (fgets(buf[!which], 8192, fp) != NULL) {
- for (p = buf[!which]; *p && *p != '\n'; p++) ;
- *p = '\0';
-
- p = buf[!which];
- while (*p && *p!=' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- if (c != '\0')
- *p++ = '\0';
-
- if (c != '!')
- c = ':';
-
- while (i < cur_groupnum) {
- if (strcmp(buf[!which],
- active[my_group[i]].name) == 0) {
- fprintf(newfp, "%s%c%s\n",
- buf[!which], c, p);
- goto foo_cont;
- }
- i++;
- }
- fprintf(newfp, "%s%c%s\n", buf[which], c, p);
- fprintf(newfp, "%s%c%s\n", buf[!which], c, p);
- break;
- foo_cont:;
- }
-
- while (fgets(buf[!which], 8192, fp) != NULL)
- fputs(buf[!which], newfp);
-
- fclose(newfp);
- fclose(fp);
- unlink(newsrc);
- link(newnewsrc, newsrc);
- unlink(newnewsrc);
- setuid(tass_uid);
- setgid(tass_gid);
- return TRUE;
- }
- }
-
- setuid(tass_uid);
- setgid(tass_gid);
-
- return FALSE;
- }
-
-
- mark_group_read(group, groupnum)
- char *group;
- int groupnum; /* index into active[] for this group */
- {
- FILE *fp;
- FILE *newfp;
- char buf[8192];
- char *p;
- char c;
- int gotit = FALSE;
-
- if (active[groupnum].max < 2)
- return;
-
- setuid(real_uid);
- setgid(real_gid);
-
- fp = fopen(newsrc, "r");
- newfp = fopen(newnewsrc, "w");
- if (newfp == NULL)
- goto mark_group_read_done;
-
- if (fp != NULL) {
- while (fgets(buf, 8192, fp) != NULL) {
- for (p = buf; *p; p++)
- if (*p == '\n') {
- *p = '\0';
- break;
- }
-
- p = buf;
- while (*p && *p != ' ' && *p != ':' && *p != '!')
- p++;
- c = *p;
- if (c != '\0')
- *p++ = '\0';
-
- if (c != '!')
- c = ':';
-
- if (strcmp(buf, group) == 0) {
- fprintf(newfp, "%s%c 1-%ld\n", buf, c,
- active[groupnum].max);
- gotit = TRUE;
- } else
- fprintf(newfp, "%s%c%s\n", buf, c, p);
- }
- fclose(fp);
- }
-
- fclose(newfp);
- unlink(newsrc);
- link(newnewsrc, newsrc);
- unlink(newnewsrc);
-
- mark_group_read_done:
- setuid(tass_uid);
- setgid(tass_gid);
- }
-
- @EOF
-
- chmod 644 main.c
-
- echo x - misc.c
- cat >misc.c <<'@EOF'
-
- #include <stdio.h>
- #include <signal.h>
- #include <pwd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include "tass.h"
-
-
- char active_file[LEN];
- char homedir[LEN];
- char userid[LEN];
- char delgroups[LEN];
- char newsrc[LEN];
- char newnewsrc[LEN];
- char indexdir[LEN];
- char my_org[LEN]; /* organization */
-
-
- /*
- * Which base note (an index into base[]) does a respnum
- * (an index into arts[]) corresponsd to?
- *
- * In other words, base[] points to an entry in arts[] which is
- * the head of a thread, linked with arts[].thread. For any q: arts[q],
- * find i such that base[i]->arts[n]->arts[o]->...->arts[q]
- */
-
- which_base(n)
- int n;
- {
- int i, j;
-
- for (i = 0; i < top_base; i++)
- for (j = base[i]; j >= 0; j = arts[j].thread)
- if (j == n)
- return i;
-
- fprintf(stderr, "can't find base article\n");
- return 0;
- }
-
-
- /*
- * Find how deep in a thread a response is. Start counting at zero
- */
-
- which_resp(n)
- int n;
- {
- int i, j;
- int num = 0;
-
- i = which_base(n);
-
- for (j = base[i]; j != -1; j = arts[j].thread)
- if (j == n)
- break;
- else
- num++;
-
- return num;
- }
-
-
- /*
- * Given an index into base[], find the number of responses for
- * that basenote
- */
-
- nresp(n)
- int n;
- {
- int i;
- int oldi = -3;
- int sum = 0;
-
- assert(n < top_base);
-
- for (i = base[n]; i != -1; i = arts[i].thread) {
- assert(i != -2);
- assert(i != oldi);
- oldi = i;
- sum++;
- }
-
- return sum - 1;
- }
-
-
- asfail(file, line, cond)
- char *file;
- int line;
- char *cond;
- {
- fprintf(stderr, "tass: assertion failure: %s (%d): %s\n",
- file, line, cond);
- exit(1);
- }
-
-
- /*
- * Make regular expressions pleasant for the masses: glob them
- */
-
- glob_name(group, grp)
- char *group;
- char *grp;
- {
- char *p, *q;
-
- /*
- * Prefix the .'s in the group name so they won't be interpreted
- * as regular expression commands. Change 'all' into '*'
- */
-
- p = group;
- q = grp;
-
- if (strncmp(p, "all", 3) == 0 && (p[3] == '.' || p[3] == '\0')) {
- *q++ = '.';
- *q++ = '*';
- p = &p[3];
- }
- while (*p != '\0') {
- if (*p == '.') {
- *q++ = '\\';
- *q++ = '.';
- p++;
-
- if (strncmp(p, "all", 3) == 0 &&
- (p[3] == '.' || p[3] == '\0')) {
- *q++ = '.';
- *q++ = '*';
- p = &p[3];
- }
- } else if (*p == '*') {
- *q++ = '.';
- *q++ = '*';
- p++;
- } else
- *q++ = *p++;
- }
- *q = '\0';
- }
-
-
- /*
- * init_selfinfo
- * Deterimines users home directory, userid, and a path
- * for an rc file in the home directory
- */
-
- init_selfinfo()
- {
- struct passwd *myentry;
- extern struct passwd *getpwuid();
- struct stat sb;
- char nam[LEN];
- char *p;
- extern char *getenv();
- FILE *fp;
-
- myentry = getpwuid(getuid());
- strcpy(userid, myentry->pw_name);
- strcpy(homedir, myentry->pw_dir);
-
- sprintf(newsrc, "%s/.newsrc", homedir);
- sprintf(newnewsrc, "%s/.newnewsrc", homedir);
- sprintf(delgroups, "%s/.delgroups", homedir);
- sprintf(indexdir, "%s/.tindex", homedir);
- sprintf(active_file, "%s/active", LIBDIR);
- if (stat(active_file, &sb) >= 0)
- goto got_active;
-
- /*
- * I hate forgetting to define LIBDIR correctly. Guess a
- * couple of likely places if it's not where LIBDIR says it is.
- */
-
- strcpy(active_file, "/usr/lib/news/active");
- if (stat(active_file, &sb) >= 0)
- goto got_active;
-
- strcpy(active_file, "/usr/local/lib/news/active");
- if (stat(active_file, &sb) >= 0)
- goto got_active;
-
- strcpy(active_file, "/usr/public/lib/news/active");
- if (stat(active_file, &sb) >= 0)
- goto got_active;
-
- /*
- * Oh well. Revert to what LIBDIR says it is to produce a
- * useful error message when read_active() fails later.
- */
-
- sprintf(active_file, "%s/active", LIBDIR);
-
- got_active:
-
- *my_org = '\0';
- p = getenv("ORGANIZATION");
- if (p != NULL) {
- strcpy(my_org, p);
- goto got_org;
- }
-
- sprintf(nam, "%s/organization", LIBDIR);
- fp = fopen(nam, "r");
-
- if (fp == NULL) {
- sprintf(nam, "/usr/lib/news/organization");
- fp = fopen(nam, "r");
- }
-
- if (fp == NULL) {
- sprintf(nam, "/usr/local/lib/news/organization");
- fp = fopen(nam, "r");
- }
-
- if (fp == NULL) {
- sprintf(nam, "/usr/public/lib/news/organization");
- fp = fopen(nam, "r");
- }
-
- if (fp == NULL) {
- sprintf(nam, "/etc/organization");
- fp = fopen(nam, "r");
- }
-
- if (fp != NULL) {
- if (fgets(my_org, LEN, fp) != NULL) {
- for (p = my_org; *p && *p != '\n'; p++) ;
- *p = '\0';
- }
- fclose(fp);
- }
-
- got_org:;
-
- }
-
-
- char *
- my_malloc(size)
- unsigned size;
- {
- char *p;
- extern char *malloc();
-
- p = malloc(size);
- if (p == NULL) {
- fprintf(stderr, "tass: out of memory\n");
- exit(1);
- }
- return p;
- }
-
-
- char *
- my_realloc(p, size)
- char *p;
- unsigned size;
- {
- extern char *malloc();
- extern char *realloc();
-
- if (p == NULL)
- p = malloc(size);
- else
- p = realloc(p, size);
-
- if (p == NULL) {
- fprintf(stderr, "tass: out of memory\n");
- exit(1);
- }
- return p;
- }
-
-
- char *
- str_save(s)
- char *s;
- {
- char *p;
-
- assert(s != NULL);
-
- p = my_malloc(strlen(s) + 1);
- strcpy(p, s);
-
- return(p);
- }
-
-
- copy_fp(a, b, prefix)
- FILE *a;
- FILE *b;
- char *prefix;
- {
- char buf[8192];
-
- while (fgets(buf, 8192, a) != NULL)
- fprintf(b, "%s%s", prefix, buf);
- }
-
-
- char *
- get_val(env, def)
- char *env; /* Environment variable we're looking for */
- char *def; /* Default value if no environ value found */
- {
- extern char *getenv();
- char *ptr;
-
- if ((ptr = getenv(env)) != NULL)
- return(ptr);
- else
- return(def);
- }
-
-
- invoke_editor(nam)
- char *nam;
- {
- char buf[200];
- static int first = TRUE;
- static char editor[200];
-
- if (first) {
- strcpy(editor, get_val("EDITOR", "/usr/bin/vi"));
- first = FALSE;
- }
-
- sprintf(buf, "%s %s", editor, nam);
- printf("%s\n", buf);
- return invoke_cmd(buf);
- }
-
-
- invoke_cmd(nam)
- char *nam;
- {
- int ret;
- #ifdef SIGTSTP
- void (*susp)();
- #endif
-
- Raw(FALSE);
- setuid(real_uid);
- setgid(real_gid);
-
- #ifdef SIGTSTP
- susp = signal(SIGTSTP, SIG_DFL);
- #endif
-
- ret = system(nam);
-
- #ifdef SIGTSTP
- signal(SIGTSTP, susp);
- #endif
-
- setuid(tass_uid);
- setgid(tass_gid);
- Raw(TRUE);
-
- return ret == 0;
- }
-
-
- shell_escape() {
- char shell[LEN];
- char *p;
- #ifdef SIGTSTP
- void (*susp)();
- #endif
-
- if (!parse_string("!", shell))
- strcpy(shell, get_val("SHELL", "/bin/sh"));
-
- for (p = shell; *p && (*p == ' ' || *p == '\t'); p++) ;
-
- if (!*p)
- strcpy(shell, get_val("SHELL", "/bin/sh"));
-
- Raw(FALSE);
-
- setuid(real_uid);
- setgid(real_gid);
-
- fputs("\r\n", stdout);
-
- #ifdef SIGTSTP
- susp = signal(SIGTSTP, SIG_DFL);
- #endif
-
- system(p);
-
- #ifdef SIGTSTP
- signal(SIGTSTP, susp);
- #endif
-
- setuid(tass_uid);
- setgid(tass_gid);
-
- Raw(TRUE);
-
- continue_prompt();
- mail_setup();
- }
-
-
- /*
- * Find the next unread response in this group
- */
-
- next_unread(n)
- int n;
- {
-
- while (n >= 0) {
- if (arts[n].unread == 1)
- return n;
- n = next_response(n);
- }
-
- return -1;
- }
-
-
- /*
- * Find the previous unread response in this thread
- */
-
- prev_unread(n)
- int n;
- {
-
- while (n >= 0) {
- if (arts[n].unread == 1)
- return n;
- n = prev_response(n);
- }
-
- return -1;
- }
-
- @EOF
-
- chmod 644 misc.c
-
- exit 0
- --
- skrenta@blekko.commodore.com
-