home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume29
/
tin
/
part04
< prev
next >
Wrap
Text File
|
1992-03-28
|
52KB
|
2,275 lines
Newsgroups: comp.sources.misc
From: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
Subject: v29i022: tin - threaded full screen newsreader v1.1P1, Part04/12
Message-ID: <1992Mar27.033058.2262@sparky.imd.sterling.com>
Date: Fri, 27 Mar 1992 03:30:58 GMT
Approved: kent@sparky.imd.sterling.com
X-Md4-Signature: ea2bff95bf5b8e6337a9782b12c580df
Submitted-by: iain%anl433.uucp@germany.eu.net (Iain J. Lea)
Posting-number: Volume 29, Issue 22
Archive-name: tin/part04
Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
Supersedes: tin: Volume 28, Issue 45-55
#!/bin/sh
# this is tin.shar.04 (part 4 of tin1.1)
# do not concatenate these parts, unpack them in order with /bin/sh
# file art.c continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 4; then
echo Please unpack part "$Scheck" next!
exit 1
else
exit 0
fi
) < _shar_seq_.tmp || exit 1
if test ! -f _shar_wnt_.tmp; then
echo 'x - still skipping art.c'
else
echo 'x - continuing file art.c'
sed 's/^X//' << 'SHAR_EOF' >> 'art.c' &&
X } else {
X error = 12;
X goto corrupt_index;
X }
X
X /*
X * Date:
X */
X if (fgets(buf, sizeof buf, fp) == NULL) {
X error = 13;
X goto corrupt_index;
X }
X
X buf[strlen (buf)-1] = '\0';
X my_strncpy (arts[top].date, buf, 12);
X
X /*
X * Archive-name:
X */
X if (fgets(buf, sizeof buf, fp) == NULL) {
X error = 14;
X goto corrupt_index;
X }
X
X if (buf[0] == '\n') {
X arts[top].archive = (char *) 0;
X } else if (buf[0] == '%') {
X n = atoi (&buf[1]);
X if (n > top || n < 0) {
X error = 15;
X goto corrupt_index;
X }
X arts[top].archive = arts[n].archive;
X } else if (buf[0] == ' ') {
X for (p = &buf[1]; *p && *p != '\n' ; p++)
X continue;
X *p = '\0';
X arts[top].archive = hash_str (&buf[1]);
X } else {
X error = 16;
X goto corrupt_index;
X }
X
X /*
X * part no.
X */
X if (fgets(buf, sizeof buf, fp) == NULL) {
X error = 17;
X goto corrupt_index;
X }
X
X if (buf[0] != ' ') {
X buf[strlen (buf)-1] = '\0';
X arts[top].part = str_dup (buf);
X }
X
X /*
X * patch no.
X */
X if (fgets(buf, sizeof buf, fp) == NULL) {
X error = 18;
X goto corrupt_index;
X }
X
X if (buf[0] != ' ') {
X buf[strlen (buf)-1] = '\0';
X arts[top].patch = str_dup (buf);
X }
X
X debug_print_header (&arts[top]);
X }
X
X fclose(fp);
X return TRUE;
X
corrupt_index:
X if (! update) {
X sprintf (msg, txt_corrupt_index, index_file, error, top);
X error_message (msg, "");
X }
X
X if (debug == 2) {
X sprintf (msg, "cp %s INDEX.BAD", index_file);
X system (msg);
X }
X
X unlink (index_file);
X top = 0;
X return FALSE;
}
X
X
/*
X * Look in the local $HOME/RCDIR/INDEXDIR (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 */
X
void find_index_file (group)
X char *group;
{
X char *p;
X FILE *fp;
X int i = 1;
X static char buf[LEN];
X char dir[LEN];
X unsigned long h;
X
X h = hash_groupname (group);
X
#ifdef NNTP_XINDEX
/* sprintf (dir, "%s/%s", spooldir, INDEXDIR);
*/
X sprintf (index_file, "/tmp/idx%d", process_id);
X return;
#else
X if (local_index) {
X strcpy (dir, indexdir);
X } else {
X sprintf (dir, "%s/%s", spooldir, INDEXDIR);
X }
#endif
X
X while (TRUE) {
X sprintf (index_file, "%s/%lu.%d", dir, h, i);
X
X if ((fp = fopen (index_file, "r")) == NULL) {
X return;
X }
X
X if (fgets (buf, sizeof (buf), fp) == NULL) {
X fclose (fp);
X return;
X }
X fclose (fp);
X
X for (p = buf; *p && *p != '\n'; p++) {
X continue;
X }
X *p = '\0';
X
X if (strcmp (buf, group) == 0) {
X return;
X }
X i++;
X }
}
X
/*
X * Run the index file updater only for the groups we've loaded.
X */
X
void do_update ()
{
X int i, j;
X char group_path[LEN];
X char *p;
X long beg_epoch, end_epoch;
X
X if (verbose) {
X time (&beg_epoch);
X }
X
X for (i = 0; i < group_top; i++) {
X strcpy(group_path, active[my_group[i]].name);
X for (p = group_path; *p; p++) {
X if (*p == '.') {
X *p = '/';
X }
X }
X if (verbose) {
X printf ("%s %s\n", (catchup ? "Catchup" : "Updating"),
X active[my_group[i]].name);
X fflush (stdout);
X }
X index_group (active[my_group[i]].name, group_path);
X if (catchup) {
X for (j = 0; j < top; j++) {
X arts[j].unread = ART_READ;
X }
X update_newsrc (active[my_group[i]].name, my_group[i], FALSE);
X }
X }
X
X if (verbose) {
X time (&end_epoch);
X sprintf (msg, "%s %d groups in %ld seconds\n",
X (catchup ? "Caughtup" : "Updated"), group_top, end_epoch - beg_epoch);
X wait_message (msg);
X }
}
X
/*
X * reload index after any articles have been killed
X */
X
void reload_index_file (group, killed)
X char *group;
X int killed;
{
X char group_path[LEN];
X char *p;
X
X if (local_index) { /* writing index in home directory */
X set_real_uid_gid (); /* so become them */
X }
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
X if (killed) {
X if (! update) {
X wait_message (txt_killing_arts);
X }
X index_file_killed = TRUE;
X setup_base (group, group_path);
X dump_index_file (group, killed);
X load_index_file (group);
X read_newsrc_line (group);
X } else {
X if (! update) {
X wait_message (txt_unkilling_arts);
X }
X find_index_file (group);
X
X unlink (index_file); /* delete index file */
X
X index_file_killed = FALSE;
X last_read_article = 0L;
X
X if (read_group (group, group_path)) {
X dump_index_file (group, killed);
X }
X }
X
X make_threads (TRUE);
X find_base (show_only_unread);
X
X if (local_index) {
X set_tin_uid_gid ();
X }
X
X return;
}
X
/*
X * convert date from ctime format to sortable format
X * "24 Jul 91 12:59:59", "Mon, 24 Jul 91 12:59:59" and
X * "Mon, 24 Jul 1991 12:59:59" are parsed and produce
X * output of the form "910724125959"
X */
X
char *parse_date (date, str)
X char *date;
X char *str;
{
X char buf[4];
X int i = 0;
X
X /* Check for extraneous day-of-week at start of date */
X while (isalpha(date[i]) || date[i] == ',' || date[i] == ' ') {
X i++;
X }
X
X if (date[i+1] == ' ') { /* ie. "2 Aug..." instead of "12 Aug... */
X str[4] = '0'; /* day */
X str[5] = date[i++];
X i++;
X } else {
X str[4] = date[i++]; /* day */
X str[5] = date[i++];
X i++;
X }
X
X buf[0] = date[i++]; /* month in Jan,Feb,.. form */
X buf[1] = date[i++];
X buf[2] = date[i++];
X buf[3] = '\0';
X
X i++;
X
X str[0] = date[i++]; /* year */
X str[1] = date[i++];
X if (isdigit(date[i])) { /* 19xx format */
X str[0] = date[i++];
X str[1] = date[i++];
X }
X
X i++;
X
X if (strcmp (buf, "Jan") == 0) { /* convert Jan to 01 etc */
X str[2] = '0';
X str[3] = '1';
X } else if (strcmp (buf, "Feb") == 0) {
X str[2] = '0';
X str[3] = '2';
X } else if (strcmp (buf, "Mar") == 0) {
X str[2] = '0';
X str[3] = '3';
X } else if (strcmp (buf, "Apr") == 0) {
X str[2] = '0';
X str[3] = '4';
X } else if (strcmp (buf, "May") == 0) {
X str[2] = '0';
X str[3] = '5';
X } else if (strcmp (buf, "Jun") == 0) {
X str[2] = '0';
X str[3] = '6';
X } else if (strcmp (buf, "Jul") == 0) {
X str[2] = '0';
X str[3] = '7';
X } else if (strcmp (buf, "Aug") == 0) {
X str[2] = '0';
X str[3] = '8';
X } else if (strcmp (buf, "Sep") == 0) {
X str[2] = '0';
X str[3] = '9';
X } else if (strcmp (buf, "Oct") == 0) {
X str[2] = '1';
X str[3] = '0';
X } else if (strcmp (buf, "Nov") == 0) {
X str[2] = '1';
X str[3] = '1';
X } else if (strcmp (buf, "Dec") == 0) {
X str[2] = '1';
X str[3] = '2';
X } else {
X str[2] = '0';
X str[3] = '0';
X }
X
X str[6] = date[i++]; /* hour */
X str[7] = date[i++];
X
X i++;
X
X str[8] = date[i++]; /* minutes */
X str[9] = date[i++];
X
X i++;
X
X str[10] = date[i++]; /* seconds */
X str[11] = date[i++];
X
X str[12] = '\0'; /* terminate string */
X
X return (str);
}
X
X
int artnum_comp (p1, p2)
X char *p1;
X char *p2;
{
X struct article_t *s1 = (struct article_t *) p1;
X struct article_t *s2 = (struct article_t *) p2;
X
X /* s1->artnum less than s2->artnum */
X if (s1->artnum < s2->artnum) {
X return -1;
X }
X /* s1->artnum greater than s2->artnum */
X if (s1->artnum > s2->artnum) {
X return 1;
X }
X return 0;
}
X
X
int subj_comp (p1, p2)
X char *p1;
X char *p2;
{
X struct article_t *s1 = (struct article_t *) p1;
X struct article_t *s2 = (struct article_t *) p2;
X
X /* return result of strcmp (reversed for descending) */
X return (sort_art_type == SORT_BY_SUBJ_ASCEND
X ? strcmp (s1->subject, s2->subject)
X : strcmp (s2->subject, s1->subject));
}
X
X
int from_comp (p1, p2)
X char *p1;
X char *p2;
{
X struct article_t *s1 = (struct article_t *) p1;
X struct article_t *s2 = (struct article_t *) p2;
X
X /* return result of strcmp (reversed for descending) */
X return (sort_art_type == SORT_BY_FROM_ASCEND
X ? strcmp (s1->from, s2->from)
X : strcmp (s2->from, s1->from));
}
X
X
int date_comp (p1, p2)
X char *p1;
X char *p2;
{
X struct article_t *s1 = (struct article_t *) p1;
X struct article_t *s2 = (struct article_t *) p2;
X /* return result of strcmp (reversed for descending) */
X return (sort_art_type == SORT_BY_DATE_ASCEND
X ? strcmp (s1->date, s2->date)
X : strcmp (s2->date, s1->date));
}
X
X
void set_article (art)
X struct article_t *art;
{
X art->subject = (char *) 0;
X art->from = (char *) 0;
X art->name = (char *) 0;
X art->date[0] = '\0';
X art->archive = (char *) 0;
X art->part = (char *) 0;
X art->patch = (char *) 0;
X art->unread = ART_UNREAD;
X art->inthread = FALSE;
X art->killed = FALSE;
X art->tagged = FALSE;
}
SHAR_EOF
echo 'File art.c is complete' &&
chmod 0600 art.c ||
echo 'restore of art.c failed'
Wc_c="`wc -c < 'art.c'`"
test 24273 -eq "$Wc_c" ||
echo 'art.c: original size 24273, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= curses.c ==============
if test -f 'curses.c' -a X"$1" != X"-c"; then
echo 'x - skipping curses.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting curses.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'curses.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : curses.c
X * Author : D.Taylor & I.Lea
X * Created : ??-??-86
X * Updated : 22-03-92
X * Notes : This is a screen management library borrowed with permission
X * from the Elm mail system (a great mailer--I highly recommend
X * it!).This library was hacked to provide what tin needs.
X * Copyright : Copyright (c) 1986-92 Dave Taylor & Iain Lea
X * The Elm Mail System - $Revision: 2.1 $ $State: Exp $
X */
X
#include <stdio.h>
#include <curses.h>
X
#define DEFAULT_LINES_ON_TERMINAL 24
#define DEFAULT_COLUMNS_ON_TERMINAL 80
X
int LINES = 23;
int COLS = 80;
int inverse_okay = TRUE;
static int _inraw = FALSE; /* are we IN rawmode? */
X
X
#ifndef INDEX_DAEMON
X
#ifndef MINIX
# include <sys/ioctl.h>
#endif
X
#define BACKSPACE '\b'
#define VERY_LONG_STRING 2500
X
#ifdef BSD
# ifndef BSD4_1
# include <sgtty.h>
# else
# include <termio.h>
# endif
#else
# ifndef SYSV
# ifndef MINIX
# ifdef sinix
# include <termios.h>
# else
# include <termio.h>
# endif
# else
# include <sgtty.h>
# endif
# endif
#endif
X
#include <ctype.h>
X
#define TTYIN 0
X
#ifdef SHORTNAMES
# define _clearinverse _clrinv
# define _cleartoeoln _clrtoeoln
# define _cleartoeos _clr2eos
#endif
X
#if defined(BSD) || defined(MINIX)
# define TCGETA TIOCGETP
# define TCSETAW TIOCSETP
X
struct sgttyb _raw_tty,
X _original_tty;
#else
# ifdef sinix
# ifndef TCGETA
# define TCGETA STCGETA
# endif
# ifndef TCSETA
# define TCSETAW STCSETAW
# endif
struct termios _raw_tty,
X _original_tty;
# else
struct termio _raw_tty,
X _original_tty;
# endif
#endif
X
static char *_clearscreen, *_moveto, *_cleartoeoln, *_cleartoeos,
X *_setinverse, *_clearinverse, *_setunderline, *_clearunderline,
X *_terminalinit, *_terminalend;
X
static int _lines,_columns;
X
static char _terminal[1024]; /* Storage for terminal entry */
static char _capabilities[1024]; /* String for cursor motion */
X
static char *ptr = _capabilities; /* for buffering */
X
int outchar (); /* char output for tputs */
extern char *tgetstr (); /* Get termcap capability */
extern char *tgoto (); /* and the goto stuff */
X
#endif /* INDEX_DAEMON */
X
#include "tin.h"
X
X
int InitScreen ()
{
#ifndef INDEX_DAEMON
X
X extern int tgetent(); /* get termcap entry */
X char termname[40], *p;
X
X if ((p = (char *) getenv ("TERM")) == NULL) {
X fprintf (stderr, "%s: TERM variable must be set to use screen capabilities\n", progname);
X return (FALSE);
X }
X if (strcpy (termname, p) == NULL) {
X fprintf (stderr,"%s: Can't get TERM variable\n", progname);
X return (FALSE);
X }
X if (tgetent (_terminal, termname) != 1) {
X fprintf (stderr,"%s: Can't get entry for TERM\n", progname);
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 _terminalinit = tgetstr ("ti", &ptr);
X _terminalend = tgetstr ("te", &ptr);
X
X InitWin ();
X
X if (!_clearscreen) {
X fprintf (stderr,
X "%s: Terminal must have clearscreen (cl) capability\n",progname);
X return (FALSE);
X }
X if (!_moveto) {
X fprintf (stderr,
X "%s: Terminal must have cursor motion (cm)\n", progname);
X return (FALSE);
X }
X if (!_cleartoeoln) {
X fprintf (stderr,
X "%s: Terminal must have clear to end-of-line (ce)\n", progname);
X return (FALSE);
X }
X if (!_cleartoeos) {
X fprintf (stderr,
X "%s: Terminal must have clear to end-of-screen (cd)\n", progname);
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 return (TRUE);
X
#else
X
X return (FALSE);
X
#endif /* INDEX_DAEMON */
}
X
/*
X * returns the number of lines and columns on the display.
X */
X
void ScreenSize (num_lines, num_columns)
X int *num_lines, *num_columns;
{
#ifndef INDEX_DAEMON
X
X if (_lines == 0) _lines = DEFAULT_LINES_ON_TERMINAL;
X if (_columns == 0) _columns = DEFAULT_COLUMNS_ON_TERMINAL;
X
X *num_lines = _lines - 1; /* assume index from zero*/
X *num_columns = _columns; /* assume index from one */
X
#endif /* INDEX_DAEMON */
}
X
void InitWin ()
{
#ifndef INDEX_DAEMON
X
X if (_terminalinit) {
X tputs (_terminalinit, 1, outchar);
X fflush (stdout);
X }
X
#endif /* INDEX_DAEMON */
}
X
void EndWin ()
{
#ifndef INDEX_DAEMON
X
X if (_terminalend) {
X tputs (_terminalend, 1, outchar);
X fflush (stdout);
X }
X
#endif /* INDEX_DAEMON */
}
X
/*
X * clear the screen: returns -1 if not capable
X */
X
void ClearScreen ()
{
#ifndef INDEX_DAEMON
X
X tputs (_clearscreen, 1, outchar);
X fflush (stdout); /* clear the output buffer */
X
#endif /* INDEX_DAEMON */
}
X
/*
X * move cursor to the specified row column on the screen.
X * 0,0 is the top left!
X */
X
void MoveCursor (row, col)
X int row, col;
{
#ifndef INDEX_DAEMON
X
X char *stuff, *tgoto();
X
X stuff = tgoto (_moveto, col, row);
X tputs (stuff, 1, outchar);
X fflush (stdout);
X
#endif /* INDEX_DAEMON */
}
X
/*
X * clear to end of line
X */
X
void CleartoEOLN ()
{
#ifndef INDEX_DAEMON
X
X tputs (_cleartoeoln, 1, outchar);
X fflush (stdout); /* clear the output buffer */
X
#endif /* INDEX_DAEMON */
}
X
/*
X * clear to end of screen
X */
X
void CleartoEOS ()
{
#ifndef INDEX_DAEMON
X
X int i;
X
X if (_cleartoeos) {
X tputs (_cleartoeos, 1, outchar);
X } else {
X for (i=_lines ; i < _lines ; i++) {
X MoveCursor (i, 0);
X CleartoEOLN ();
X }
X }
X fflush (stdout); /* clear the output buffer */
X
#endif /* INDEX_DAEMON */
}
X
/*
X * set inverse video mode
X */
X
void StartInverse ()
{
#ifndef INDEX_DAEMON
X
X if (_setinverse && inverse_okay)
X tputs (_setinverse, 1, outchar);
X fflush (stdout);
X
#endif /* INDEX_DAEMON */
}
X
/*
X * compliment of startinverse
X */
X
void EndInverse ()
{
#ifndef INDEX_DAEMON
X
X if (_clearinverse && inverse_okay)
X tputs (_clearinverse, 1, outchar);
X fflush (stdout);
X
#endif /* INDEX_DAEMON */
}
X
/*
X * returns either 1 or 0, for ON or OFF
X */
X
int RawState()
{
X return (_inraw);
}
X
/*
X * state is either TRUE or FALSE, as indicated by call
X */
X
void Raw(state)
X int state;
{
#ifndef INDEX_DAEMON
X
X if (state == FALSE && _inraw) {
X (void) ioctl(TTYIN, TCSETAW, &_original_tty);
X _inraw = 0;
X }
X else if (state == TRUE && ! _inraw) {
X
X (void) ioctl(TTYIN, TCGETA, &_original_tty); /** current setting **/
X
X (void) ioctl(TTYIN, TCGETA, &_raw_tty); /** again! **/
#if defined(BSD) || defined(MINIX)
X _raw_tty.sg_flags &= ~(ECHO | CRMOD); /* echo off */
X _raw_tty.sg_flags |= CBREAK; /* raw on */
#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 */
#endif
X
X (void) ioctl(TTYIN, TCSETAW, &_raw_tty);
X
X _inraw = 1;
X }
X
#endif /* INDEX_DAEMON */
}
X
/*
X * read a character with Raw mode set!
X */
X
int ReadCh()
{
#ifndef INDEX_DAEMON
X
X register int result;
X char ch;
X
#ifdef READ_CHAR_HACK
#undef getc
X ch = getc (stdin);
X return ((ch == EOF) ? EOF : ch & 0xFF);
#else
X result = read(0, &ch, 1);
X return((result <= 0 ) ? EOF : ch & 0xFF);
#endif
X
#endif /* INDEX_DAEMON */
}
X
/*
X * output a character. From tputs... (Note: this CANNOT be a macro!)
X */
X
int outchar(c)
X char c;
{
X putc(c, stdout);
}
SHAR_EOF
chmod 0600 curses.c ||
echo 'restore of curses.c failed'
Wc_c="`wc -c < 'curses.c'`"
test 7612 -eq "$Wc_c" ||
echo 'curses.c: original size 7612, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= debug.c ==============
if test -f 'debug.c' -a X"$1" != X"-c"; then
echo 'x - skipping debug.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting debug.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'debug.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : debug.c
X * Author : I.Lea
X * Created : 01-04-91
X * Updated : 07-03-92
X * Notes : debug routines
X * Copyright : (c) Copyright 1991-92 by Iain Lea
X * You may freely copy or redistribute this software,
X * so long as there is no profit made from its use, sale
X * trade or reproduction. You may not change this copy-
X * right notice, and it must be included in any copy made
X */
X
#include "tin.h"
#include "nntp.h"
X
int debug;
X
/*
X * nntp specific debug routines
X */
X
void debug_nntp (func, line)
X char *func;
X char *line;
{
#ifdef DEBUG
X FILE *fp;
X
X if (debug != 1)
X return;
X
X if ((fp = fopen ("/tmp/NNTP","a+")) != NULL) {
X fprintf (fp,"%s: %s\n", func, line);
X fclose (fp);
X chmod ("/tmp/NNTP", 0666);
X }
#endif
}
X
X
void debug_nntp_respcode (respcode)
X int respcode;
{
#ifdef DEBUG
X debug_nntp ("get_respcode", nntp_respcode (respcode));
#endif
}
X
/*
X * tin specific debug routines
X */
X
void debug_print_arts ()
{
#ifdef DEBUG
X int i;
X
X if (debug != 2)
X return;
X
X for (i = 0; i < top; i++) { /* for each group */
X debug_print_header (&arts[i]);
X }
#endif
}
X
X
void debug_print_header (s)
X struct article_t *s;
{
#ifdef DEBUG
X FILE *fp;
X
X if (debug != 2)
X return;
X
X if ((fp = fopen ("/tmp/ARTS","a+")) != NULL) {
X fprintf (fp,"art=[%5ld] killed=[%s]\n", s->artnum,
X (s->tagged ? "TRUE" : "FALSE"));
X fprintf (fp,"subj=[%-38s]\n", s->subject);
X fprintf (fp,"from=[%s] name=[%s]\n", s->from, s->name);
X if (s->archive) {
X fprintf (fp, "arch=[%-38s] ", s->archive);
X } else {
X fprintf (fp, "arch=[] ");
X }
X if (s->part) {
X fprintf (fp, "part=[%s] ", s->part);
X } else {
X fprintf (fp, "part=[] ");
X }
X if (s->patch) {
X fprintf (fp, "patch=[%s]\n", s->patch);
X } else {
X fprintf (fp, "patch=[]\n");
X }
X fprintf (fp,"thread=[%d] inthread=[%d] unread=[%d]\n",
X s->thread, s->inthread, s->unread);
/* fprintf (fp,"thread=[%s] inthread=[%s] unread=[%s]\n",
X (s->thread == ART_NORMAL ? "ART_NORMAL" : "ART_EXPIRED"),
X (s->inthread ? "TRUE" : "FALSE"),
X (s->unread ? "TRUE" : "FALSE"));
*/
X fflush (fp);
X fclose (fp);
X chmod ("/tmp/DUMP", 0666);
X }
#endif
}
X
X
void debug_print_comment (comment)
X char *comment;
{
#ifdef DEBUG
X FILE *fp;
X
X if (debug != 2)
X return;
X
X if ((fp = fopen ("/tmp/BASE","a+")) != NULL) {
X fprintf (fp,"\n%s\n\n", comment);
X fflush (fp);
X fclose (fp);
X chmod ("/tmp/BASE", 0666);
X }
#endif
}
X
X
void debug_print_base ()
{
#ifdef DEBUG
X FILE *fp;
X int i;
X
X if (debug != 2)
X return;
X
X if ((fp = fopen ("/tmp/BASE","a+")) != NULL) {
X for (i = 0; i < top_base; i++) {
X fprintf (fp, "base[%3d]=[%5ld]\n",i,base[i]);
X }
X fflush (fp);
X fclose (fp);
X chmod ("/tmp/BASE", 0666);
X }
#endif
}
X
X
void debug_print_active ()
{
#ifdef DEBUG
X FILE *fp;
X int i;
X
X if (debug > 0)
X return;
X
X if ((fp = fopen ("/tmp/ACTIVE","w")) != NULL) {
X for (i = 0; i < num_active; i++) { /* for each group */
X fprintf (fp, "[%4d]=[%-28s] max=[%4ld] min=[%4ld] mod=[%c] nxt=[%4d] flag=[%d] read=[%d] thread=[%d]\n",
X i, active[i].name, active[i].max, active[i].min,
X active[i].moderated, active[i].next, active[i].flag,
X active[i].read, active[i].thread);
X }
X fflush (fp);
X fclose (fp);
X chmod ("/tmp/ACTIVE", 0666);
X }
#endif
}
SHAR_EOF
chmod 0600 debug.c ||
echo 'restore of debug.c failed'
Wc_c="`wc -c < 'debug.c'`"
test 3371 -eq "$Wc_c" ||
echo 'debug.c: original size 3371, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= feed.c ==============
if test -f 'feed.c' -a X"$1" != X"-c"; then
echo 'x - skipping feed.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting feed.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'feed.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : feed.c
X * Author : I.Lea
X * Created : 31-08-91
X * Updated : 18-03-92
X * Notes : provides same interface to mail,pipe,print and save commands
X * Copyright : (c) Copyright 1991-92 by Iain Lea
X * You may freely copy or redistribute this software,
X * so long as there is no profit made from its use, sale
X * trade or reproduction. You may not change this copy-
X * right notice, and it must be included in any copy made
X */
X
#include "tin.h"
X
extern char *glob_group; /* Group name */
extern char note_h_date[LEN]; /* Date: */
extern char note_h_newsgroups[LEN]; /* Newsgroups: */
extern char note_h_subj[LEN]; /* Subject: */
extern FILE *note_fp; /* the body of the current article */
extern int note_end; /* end of article ? */
extern int note_page; /* what page we're on */
extern long note_mark[MAX_PAGES]; /* ftells on beginnings of pages */
X
char default_mail_address[LEN];
char default_pipe_command[LEN];
char default_save_file[LEN];
char default_regex_pattern[LEN];
char proc_ch_default; /* set in change_rcfile () */
X
X
void feed_articles (function, level, prompt, respnum, group_path)
X int function;
X int level;
X char *prompt;
X int respnum;
X char *group_path;
{
#ifndef INDEX_DAEMON
X
X char address[LEN];
X char command[LEN];
X char file[LEN], *p;
X char mailbox[LEN];
X char pattern[LEN];
X char ch = 'a', ch_default = 'a';
X char proc_ch = proc_ch_default;
X FILE *fp;
X int b, i, j, count = 1;
X int confirm;
X int is_mailbox = FALSE;
X int orig_note_end;
X int orig_note_page;
X int patlen;
X int ret1 = FALSE;
X int ret2 = FALSE;
X int redraw_screen = FALSE;
X
X if (level == PAGE_LEVEL) {
X orig_note_end = note_end;
X orig_note_page = note_page;
X }
X
X b = which_thread (respnum);
X
X if (num_of_tagged_files) {
X ch_default = 'T';
X }
X if (! num_of_tagged_files && num_of_responses (b)) {
X ch_default = 't';
X }
X
X if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0) ||
X (save_archive_name == TRUE && function != FEED_SAVE) ||
X ch_default == 'T') {
X do {
X sprintf (msg, "%s%s%c", prompt, txt_art_thread_regex_tag, ch_default);
X wait_message (msg);
X MoveCursor (LINES, (int) strlen (msg)-1);
X if ((ch = (char) ReadCh ()) == CR)
X ch = ch_default;
X } while (ch != ESC && ch != 'a' && ch != 't' && ch != 'T' && ch != 'r' && ch != 'e');
X } else {
X file[0] = '\0';
X ch = ch_default;
X if (str_str (glob_group, "sources", 7)) {
X proc_ch = 's'; /* *source* group */
X } else if (str_str (glob_group, "binaries", 8)) {
X proc_ch = 'u'; /* *binaries* group */
X } else {
X proc_ch = 's';
X }
X }
X
X if (ch == 'e' || ch == ESC) { /* exit */
X clear_message ();
X return;
X }
X
X if (ch == 'r') {
X sprintf (msg, txt_feed_pattern, default_regex_pattern);
X if (! prompt_string (msg, pattern)) {
X clear_message ();
X return;
X }
X if (strlen (pattern)) {
X my_strncpy (default_regex_pattern, pattern, LEN);
X } else {
X if (default_regex_pattern[0]) {
X my_strncpy (pattern, default_regex_pattern, LEN);
X } else {
X info_message (txt_no_match);
X return;
X }
X }
X }
X
X switch (function) {
X case FEED_MAIL:
X sprintf (msg, txt_mail_art_to, default_mail_address);
X if (! prompt_string (msg, address)) {
X clear_message ();
X return;
X }
X if (strlen (address)) {
X strcpy (default_mail_address, address);
X } else {
X if (default_mail_address[0]) {
X strcpy (address, default_mail_address);
X } else {
X info_message (txt_no_mail_address);
X return;
X }
X }
X break;
X case FEED_PIPE:
X sprintf (msg, txt_pipe_to_command, default_pipe_command);
X if (! prompt_string (msg, command)) {
X clear_message ();
X return;
X }
X if (strlen (command)) {
X strcpy (default_pipe_command, command);
X } else {
X if (default_pipe_command[0]) {
X strcpy (command, default_pipe_command);
X } else {
X info_message (txt_no_command);
X return;
X }
X }
X
X if ((fp = popen (command, "w")) == NULL) {
X error_message (txt_command_failed_s, command);
X return;
X }
X wait_message (txt_piping);
X Raw (FALSE);
X break;
X case FEED_PRINT:
X if (default_printer) {
#ifdef sinix
X sprintf (command, "%s -dru=%s %s",
X printer, get_val ("PRINTER","ps"), redirect_output);
#else
X sprintf (command, "%s -P%s %s",
X printer, get_val ("PRINTER","ps"), redirect_output);
#endif
X } else {
X if (cmd_line_printer[0]) {
X sprintf (command, "%s %s",
X cmd_line_printer, redirect_output);
X } else {
X sprintf (command, "%s %s",
X printer, redirect_output);
X }
X }
X if ((fp = popen (command, "w")) == NULL) {
X error_message (txt_command_failed_s, command);
X return;
X }
X break;
X case FEED_SAVE: /* ask user for filename */
X free_save_array ();
X if ((save_archive_name == FALSE || arts[respnum].archive == (char *) 0)) {
X sprintf (msg, txt_save_filename, default_save_file);
X if (! prompt_string (msg, file)) {
X clear_message ();
X return;
X }
X if (strlen (file)) {
X strcpy (default_save_file, file);
X } else {
X if (default_save_file[0]) {
X strcpy (file, default_save_file);
X } else {
X info_message (txt_no_filename);
X return;
X }
X }
X for (p = file; *p && (*p == ' ' || *p == '\t'); p++) {
X continue;
X }
X if (! *p) {
X info_message (txt_no_filename);
X return;
X }
X if ((file[0] == '~' || file[0] == '+') && strlen (file) == 1) {
X info_message (txt_no_filename);
X return;
X }
X is_mailbox = create_path (file);
X if (is_mailbox) {
X if ((int) strlen (file) > 1) {
X my_strncpy (mailbox, file+1, LEN);
X } else {
X my_strncpy (mailbox, glob_group, LEN);
X /*
X * convert 1st letter to uppercase
X */
X if (mailbox[0] >= 'a' && mailbox[0] <= 'z') {
X mailbox[0] = mailbox[0] - 32;
X }
X }
X my_strncpy (file, mailbox, LEN);
X } else { /* ask for post processing type */
X do {
X sprintf (msg, "%s%c", txt_post_process_type, proc_ch_default);
X wait_message (msg);
X MoveCursor (LINES, (int) strlen (msg)-1);
X if ((proc_ch = (char) ReadCh ()) == CR)
X proc_ch = proc_ch_default;
X } while (proc_ch != 'n' && proc_ch != 's' &&
X proc_ch != 'u' && proc_ch != 'U');
X }
X }
X clear_message ();
X break;
X }
X
X switch (ch) {
X case 'a': /* article */
X if (level == GROUP_LEVEL) {
X note_page = art_open (arts[respnum].artnum, group_path);
X }
X switch (function) {
X case FEED_MAIL:
X redraw_screen = mail_to_someone (address, TRUE);
X break;
X case FEED_PIPE:
X fseek (note_fp, 0L, 0);
X copy_fp (note_fp, fp, (char *) 0);
X break;
X case FEED_PRINT:
X print_file (fp, respnum, 1);
X pclose (fp);
X break;
X case FEED_SAVE:
X wait_message (txt_saving);
X add_to_save_list (0, &arts[respnum], is_mailbox, file);
X (void) save_art_to_file (respnum, 0, FALSE, (char *) 0);
X break;
X }
X if (mark_saved_read) {
X arts[respnum].unread = ART_READ;
X }
X if (level == GROUP_LEVEL) {
X art_close ();
X }
X break;
X
X case 't': /* thread */
X confirm = TRUE;
X for (i = (int) base[b]; i >= 0; i = arts[i].thread) {
X if (function == FEED_PRINT) {
X if ((fp = popen (command, "w")) == NULL) {
X error_message (txt_command_failed_s, command);
X return;
X }
X }
X if (level == PAGE_LEVEL) {
X art_close ();
X }
X note_page = art_open (arts[i].artnum, group_path);
X switch (function) {
X case FEED_MAIL:
X mail_to_someone (address, confirm);
X confirm = FALSE;
X break;
X case FEED_PIPE:
X fseek (note_fp, 0L, 0);
X copy_fp (note_fp, fp, (char *) 0);
X break;
X case FEED_PRINT:
X print_file (fp, respnum, count);
X count++;
X pclose (fp);
X break;
X case FEED_SAVE:
X add_to_save_list (i, &arts[i], is_mailbox, file);
X break;
X }
X if (mark_saved_read) {
X arts[i].unread = ART_READ;
X }
X art_close ();
X }
X if (function == FEED_SAVE) {
X sort_save_list ();
X (void) save_thread_to_file (is_mailbox, group_path);
X }
X break;
X
X case 'T': /* tagged articles */
X confirm = TRUE;
X for (i=1 ; i <= num_of_tagged_files ; i++) {
X for (j=0 ; j < top ; j++) {
X if (arts[j].tagged && arts[j].tagged == i) {
X if (function == FEED_PRINT) {
X if ((fp = popen (command, "w")) == NULL) {
X error_message (txt_command_failed_s, command);
X return;
X }
X }
X if (level == PAGE_LEVEL) {
X art_close ();
X }
X note_page = art_open (arts[j].artnum, group_path);
X switch (function) {
X case FEED_MAIL:
X mail_to_someone (address, confirm);
X confirm = FALSE;
X break;
X case FEED_PIPE:
X fseek (note_fp, 0L, 0);
X copy_fp (note_fp, fp, (char *) 0);
X break;
X case FEED_PRINT:
X print_file (fp, respnum, count);
X count++;
X pclose (fp);
X break;
X case FEED_SAVE:
X add_to_save_list (j, &arts[j], is_mailbox, file);
X break;
X }
X if (mark_saved_read) {
X arts[j].unread = ART_READ;
X }
X art_close ();
X }
X }
X }
X if (function == FEED_SAVE) {
X (void) save_regex_arts (is_mailbox, group_path);
X }
X break;
X
X case 'r': /* regex pattern matched articles */
X confirm = TRUE;
X patlen = strlen (pattern);
X for (i=0 ; i < top ; i++) {
#ifdef NO_REGEX
X if (str_str (arts[i].subject, pattern, patlen) != 0) {
#else
X if (wildmat (arts[i].subject, pattern)) {
#endif
X if (function == FEED_PRINT) {
X if ((fp = popen (command, "w")) == NULL) {
X error_message (txt_command_failed_s, command);
X return;
X }
X }
X if (level == PAGE_LEVEL) {
X art_close ();
X }
X note_page = art_open (arts[i].artnum, group_path);
X switch (function) {
X case FEED_MAIL:
X mail_to_someone (address, confirm);
X confirm = FALSE;
X break;
X case FEED_PIPE:
X fseek (note_fp, 0L, 0);
X copy_fp (note_fp, fp, (char *) 0);
X break;
X case FEED_PRINT:
X print_file (fp, respnum, count);
X count++;
X pclose (fp);
X break;
X case FEED_SAVE:
X add_to_save_list (i, &arts[i], is_mailbox, file);
X break;
X }
X if (mark_saved_read) {
X arts[i].unread = ART_READ;
X }
X art_close ();
X }
X }
X if (function == FEED_SAVE) {
X sort_save_list ();
X (void) save_regex_arts (is_mailbox, group_path);
X }
X break;
X }
X
X redraw_screen = mail_check (); /* in case of sending to oneself */
X
X switch (function) {
X case FEED_PIPE:
X pclose (fp);
X Raw (TRUE);
X continue_prompt ();
X redraw_screen = TRUE;
X break;
X case FEED_SAVE:
X if (proc_ch != 'n' && is_mailbox == FALSE) {
X ret2 = post_process_files (proc_ch);
X }
X free_save_array ();
X break;
X }
X
X untag_all_articles ();
X
X if (level == GROUP_LEVEL) {
X ret1 = (mark_saved_read ? TRUE : FALSE);
X }
X if ((ret1 || ret2) && is_mailbox == FALSE) {
X redraw_screen = TRUE;
X }
X
X if (level == PAGE_LEVEL) {
X if (ch != 'a') {
X note_page = art_open (arts[respnum].artnum, group_path);
X }
X note_end = orig_note_end;
X note_page = orig_note_page;
X fseek (note_fp, note_mark[note_page], 0);
X if (redraw_screen) {
X if (note_page == 0) {
X show_note_page (respnum, glob_group);
X } else {
X redraw_page (respnum, glob_group);
X }
X } else {
X if (function == FEED_PIPE) {
X clear_message ();
X }
X }
X } else {
X if (redraw_screen) {
X show_group_page (glob_group);
X }
X }
X if (function == FEED_PRINT) {
X info_message (txt_printed);
X }
X
#endif /* INDEX_DAEMON */
}
X
X
void print_file (fp, respnum, count)
X FILE *fp;
X int respnum;
X int count;
{
X sprintf (msg, "%s%d", txt_printing, count);
X wait_message (msg);
X
X if (print_header) {
X fseek(note_fp, 0L, 0);
X } else {
X fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
X fprintf (fp, "From: %s (%s)\n",
X arts[respnum].from,arts[respnum].name);
X fprintf (fp, "Subject: %s\n", note_h_subj);
X fprintf (fp, "Date: %s\n\n", note_h_date);
X fseek (note_fp, note_mark[0], 0);
X }
X copy_fp (note_fp, fp, (char *) 0);
}
SHAR_EOF
chmod 0600 feed.c ||
echo 'restore of feed.c failed'
Wc_c="`wc -c < 'feed.c'`"
test 12199 -eq "$Wc_c" ||
echo 'feed.c: original size 12199, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= getline.c ==============
if test -f 'getline.c' -a X"$1" != X"-c"; then
echo 'x - skipping getline.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting getline.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'getline.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : getline.c
X * Author : Chris Thewalt / Iain Lea
X * Created : 09-11-91
X * Updated : 13-03-92
X * Notes : emacs style line editing input package.
X * Copyright : (c) Copyright 1991-92 by Chris Thewalt & Iain Lea
X * Permission to use, copy, modify, and distribute this
X * software for any purpose and without fee is hereby
X * granted, provided that the above copyright notices
X * appear in all copies and that both the copyright
X * notice and this permission notice appear in supporting
X * documentation. This software is provided "as is" without
X * express or implied warranty.
X */
X
#include "tin.h"
X
extern int isatty ();
X
#define BUF_SIZE 1024
#define SCROLL 30
#define TABSIZE 4
#ifndef HIST_SIZE
#define HIST_SIZE 100
#endif
X
#define CTRL_A '\001'
#define CTRL_B '\002'
#define CTRL_D '\004'
#define CTRL_E '\005'
#define CTRL_F '\006'
#define CTRL_H '\010'
#define CTRL_K '\013'
#define CTRL_L '\014'
#define CTRL_R '\022'
#define CTRL_N '\016'
#define CTRL_P '\020'
#define TAB '\t'
#define DEL '\177'
X
char *hist_buf[HIST_SIZE];
int hist_pos, hist_last;
static char gl_buf[BUF_SIZE]; /* input buffer */
static char *gl_prompt; /* to save the prompt string */
static int gl_init_done = 0; /* -1 is terminal, 1 is batch */
static int gl_width = 0; /* net size available for input */
static int gl_pos, gl_cnt = 0; /* position and size of input */
X
#if __STDC__
X
static int gl_tab (char *, int, int *);
static void gl_redraw (void);
static void gl_addchar (int);
static void gl_newline (void);
static void gl_fixup (int, int);
static void gl_del (int);
static void gl_kill (void);
static void hist_add (void);
static void hist_init (void);
static void hist_next (void);
static void hist_prev (void);
X
int (*gl_in_hook)(char *) = 0;
int (*gl_out_hook)(char *) = 0;
int (*gl_tab_hook)(char *, int, int *) = gl_tab;
X
#else
X
static int gl_tab ();
static void gl_redraw ();
static void gl_addchar ();
static void gl_newline ();
static void gl_fixup ();
static void gl_del ();
static void gl_kill ();
static void hist_add ();
static void hist_init ();
static void hist_next ();
static void hist_prev ();
X
int (*gl_in_hook)() = 0;
int (*gl_out_hook)() = 0;
int (*gl_tab_hook)() = gl_tab;
X
#endif
X
X
#if __STDC__
char *getline (char *prompt, int number_only, char *str)
#else
char *getline (prompt, number_only, str)
X char *prompt;
X int number_only;
X char *str;
#endif
{
X int c, i, loc, tmp;
X
X if (! gl_init_done) {
X gl_init_done = 1;
X hist_init ();
X }
X
X if (prompt == (char *) 0) {
X prompt = "";
X }
X gl_buf[0] = 0; /* used as end of input indicator */
X gl_fixup (-1, 0); /* this resets gl_fixup */
X gl_width = COLS - strlen (prompt);
X gl_prompt = prompt;
X gl_pos = gl_cnt = 0;
X
X fputs (prompt, stdout);
X fflush (stdout);
X
X if (gl_in_hook) {
X loc = gl_in_hook (gl_buf);
X if (loc >= 0)
X gl_fixup (0, BUF_SIZE);
X }
X if (str != (char *) 0) {
X for (i=0 ; str[i] ; i++)
X gl_addchar (str[i]);
X }
X while ((c = ReadCh ()) != EOF) {
X if (isprint (c)) {
X if (number_only) {
X if (isdigit (c) && gl_cnt < 6) { /* num < 100000 */
X gl_addchar (c);
X } else {
X ring_bell ();
X }
X } else {
X gl_addchar (c);
X }
X } else {
X switch (c) {
X case ESC: /* abort */
X return (char *) 0;
X break;
X case '\n': /* newline */
X case '\r':
X gl_newline ();
X return gl_buf;
X break;
X case CTRL_A:
X gl_fixup (-1, 0);
X break;
X case CTRL_B:
X gl_fixup (-1, gl_pos-1);
X break;
X case CTRL_D:
X if (gl_cnt == 0) {
X gl_buf[0] = 0;
X fputc ('\n', stdout);
X return gl_buf;
X } else {
X gl_del (0);
X }
X break;
X case CTRL_E:
X gl_fixup (-1, gl_cnt);
X break;
X case CTRL_F:
X gl_fixup (-1, gl_pos+1);
X break;
X case CTRL_H:
X case DEL:
X gl_del (-1);
X break;
X case TAB:
X if (gl_tab_hook) {
X tmp = gl_pos;
X loc = gl_tab_hook (gl_buf, strlen (gl_prompt), &tmp);
X if (loc >= 0 || tmp != gl_pos)
X gl_fixup (loc, tmp);
X }
X break;
X case CTRL_K:
X gl_kill ();
X break;
X case CTRL_L:
X case CTRL_R:
X gl_redraw ();
X break;
X case CTRL_N:
X hist_next ();
X break;
X case CTRL_P:
X hist_prev ();
X break;
X default:
X ring_bell ();
X break;
X }
X }
X }
X return gl_buf;
}
X
/*
X * adds the character c to the input buffer at current location if
X * the character is in the allowed template of characters
X */
X
#if __STDC__
static void gl_addchar (int c)
#else
static void gl_addchar (c)
X int c;
#endif
{
X int i;
X
X if (gl_cnt >= BUF_SIZE - 1) {
X error_message ("getline: input buffer overflow", "");
X exit (1);
X }
X
X for (i=gl_cnt; i >= gl_pos; i--) {
X gl_buf[i+1] = gl_buf[i];
X }
X gl_buf[gl_pos] = c;
X gl_fixup (gl_pos, gl_pos+1);
}
X
/*
X * Cleans up entire line before returning to caller. A \n is appended.
X * If line longer than screen, we redraw starting at beginning
X */
X
static void gl_newline ()
{
X int change = gl_cnt;
X int len = gl_cnt;
X int loc = gl_width - 5; /* shifts line back to start position */
X
X if (gl_cnt >= BUF_SIZE - 1) {
X error_message ("getline: input buffer overflow", "");
X exit (1);
X }
X hist_add (); /* only adds if nonblank */
X if (gl_out_hook) {
X change = gl_out_hook (gl_buf);
X len = strlen (gl_buf);
X }
X if (loc > len)
X loc = len;
X gl_fixup (change, loc); /* must do this before appending \n */
X gl_buf[len] = '\0';
}
X
/*
X * Delete a character. The loc variable can be:
X * -1 : delete character to left of cursor
X * 0 : delete character under cursor
X */
X
#if __STDC__
static void gl_del (int loc)
#else
static void gl_del (loc)
X int loc;
#endif
{
X int i;
X
X if (loc == -1 && gl_pos > 0 || loc == 0 && gl_pos < gl_cnt) {
X for (i=gl_pos+loc; i < gl_cnt; i++)
X gl_buf[i] = gl_buf[i+1];
X gl_fixup (gl_pos+loc, gl_pos+loc);
X } else {
X ring_bell ();
X }
}
X
/*
X * delete from current position to the end of line
X */
X
static void gl_kill ()
{
X if (gl_pos < gl_cnt) {
X gl_buf[gl_pos] = '\0';
X gl_fixup (gl_pos, gl_pos);
X } else {
X ring_bell ();
X }
}
X
/*
X * emit a newline, reset and redraw prompt and current input line
X */
X
static void gl_redraw ()
{
X if (gl_init_done == -1) {
X fputc ('\n', stdout);
X fputs (gl_prompt, stdout);
X gl_pos = 0;
X gl_fixup (0, BUF_SIZE);
X }
}
X
/*
X * This function is used both for redrawing when input changes or for
X * moving within the input line. The parameters are:
X * change : the index of the start of changes in the input buffer,
X * with -1 indicating no changes.
X * cursor : the desired location of the cursor after the call.
X * A value of BUF_SIZE can be used to indicate the cursor
X * should move just past the end of the input line.
X */
X
#if __STDC__
static void gl_fixup (int change, int cursor)
#else
static void gl_fixup (change, cursor)
X int change;
X int cursor;
#endif
{
X static int gl_shift; /* index of first on screen character */
X static int off_right; /* true if more text right of screen */
X static int off_left; /* true if more text left of screen */
X int left = 0, right = -1; /* bounds for redraw */
X int pad; /* how much to erase at end of line */
X int backup; /* how far to backup before fixing */
X int new_shift; /* value of shift based on cursor */
X int extra; /* adjusts when shift (scroll) happens */
X int i;
X
X if (change == -1 && cursor == 0 && gl_buf[0] == 0) { /* reset */
X gl_shift = off_right = off_left = 0;
X return;
X }
X pad = (off_right) ? gl_width - 1 : gl_cnt - gl_shift; /* old length */
X backup = gl_pos - gl_shift;
X if (change >= 0) {
X gl_cnt = strlen (gl_buf);
X if (change > gl_cnt)
X change = gl_cnt;
X }
X if (cursor > gl_cnt) {
X if (cursor != BUF_SIZE) /* BUF_SIZE means end of line */
X ring_bell ();
X cursor = gl_cnt;
X }
X if (cursor < 0) {
X ring_bell ();
X cursor = 0;
X }
X if (off_right || off_left && cursor < gl_shift + gl_width - SCROLL / 2)
X extra = 2; /* shift the scrolling boundary */
X else
X extra = 0;
X new_shift = cursor + extra + SCROLL - gl_width;
X if (new_shift > 0) {
X new_shift /= SCROLL;
X new_shift *= SCROLL;
X } else
X new_shift = 0;
X if (new_shift != gl_shift) { /* scroll occurs */
X gl_shift = new_shift;
X off_left = (gl_shift) ? 1 : 0;
X off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
X left = gl_shift;
X right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
X } else if (change >= 0) { /* no scroll, but text changed */
X if (change < gl_shift + off_left) {
X left = gl_shift;
X } else {
X left = change;
X backup = gl_pos - change;
X }
X off_right = (gl_cnt > gl_shift + gl_width - 1)? 1 : 0;
X right = (off_right) ? gl_shift + gl_width - 2 : gl_cnt;
X }
X pad -= (off_right) ? gl_width - 1 : gl_cnt - gl_shift;
X pad = (pad < 0)? 0 : pad;
X if (left <= right) { /* clean up screen */
X for (i=0; i < backup; i++)
X fputc ('\b', stdout);
X if (left == gl_shift && off_left) {
X fputc ('$', stdout);
X left++;
X }
X for (i=left; i < right; i++)
X fputc (gl_buf[i], stdout);
X if (off_right) {
X fputc ('$', stdout);
X gl_pos = right + 1;
X } else {
X for (i=0; i < pad; i++) /* erase remains of prev line */
X fputc (' ', stdout);
X gl_pos = right + pad;
X }
X }
X i = gl_pos - cursor; /* move to final cursor location */
X if (i > 0) {
X while (i--)
X fputc ('\b', stdout);
X } else {
X for (i=gl_pos; i < cursor; i++)
X fputc (gl_buf[i], stdout);
X }
X fflush (stdout);
X gl_pos = cursor;
}
X
/*
X * default tab handler, acts like tabstops every TABSIZE cols
X */
X
#if __STDC__
static int gl_tab (char *buf, int offset, int *loc)
#else
static int gl_tab (buf, offset, loc)
X char *buf;
X int offset;
X int *loc;
#endif
{
X int i, count, len;
X
X len = strlen (buf);
X count = TABSIZE - (offset + *loc) % TABSIZE;
X for (i=len; i >= *loc; i--)
X buf[i+count] = buf[i];
X for (i=0; i < count; i++)
X buf[*loc+i] = ' ';
X i = *loc;
X *loc = i + count;
X return i;
}
X
/*
X * History functions
X */
X
static void hist_init ()
{
X int i;
X
X for (i=0; i < HIST_SIZE; i++)
X hist_buf[i] = (char *) 0;
}
X
X
static void hist_add ()
{
X char *p = gl_buf;
X
X while (*p == ' ' || *p == '\t') /* only save nonblank line */
X p++;
X if (*p) {
X hist_buf[hist_last] = str_dup (gl_buf);
X hist_last = (hist_last + 1) % HIST_SIZE;
X if (hist_buf[hist_last]) { /* erase next location */
X free(hist_buf[hist_last]);
X hist_buf[hist_last] = (char *) 0;
X }
X }
X hist_pos = hist_last;
}
X
/*
X * loads previous hist entry into input buffer, sticks on first
X */
X
static void hist_prev ()
{
X int next;
X
X next = (hist_pos - 1 + HIST_SIZE) % HIST_SIZE;
X if (next != hist_last) {
X if (hist_buf[next]) {
X hist_pos = next;
X strcpy (gl_buf, hist_buf[hist_pos]);
X } else {
X ring_bell ();
X }
X } else {
X ring_bell ();
X }
X if (gl_in_hook)
X gl_in_hook (gl_buf);
X gl_fixup (0, BUF_SIZE);
}
X
/*
X * loads next hist entry into input buffer, clears on last
X */
X
static void hist_next ()
{
X if (hist_pos != hist_last) {
X hist_pos = (hist_pos + 1) % HIST_SIZE;
X if (hist_buf[hist_pos]) {
X strcpy (gl_buf, hist_buf[hist_pos]);
X } else {
X gl_buf[0] = 0;
X }
X } else {
X ring_bell ();
X }
X if (gl_in_hook)
X gl_in_hook (gl_buf);
X gl_fixup (0, BUF_SIZE);
}
SHAR_EOF
chmod 0600 getline.c ||
echo 'restore of getline.c failed'
Wc_c="`wc -c < 'getline.c'`"
test 11438 -eq "$Wc_c" ||
echo 'getline.c: original size 11438, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= group.c ==============
if test -f 'group.c' -a X"$1" != X"-c"; then
echo 'x - skipping group.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting group.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'group.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : group.c
X * Author : I.Lea & R.Skrenta
X * Created : 01-04-91
X * Updated : 22-03-92
X * Notes :
X * Copyright : (c) Copyright 1991-92 by Iain Lea & Rich Skrenta
X * You may freely copy or redistribute this software,
X * so long as there is no profit made from its use, sale
X * trade or reproduction. You may not change this copy-
X * right notice, and it must be included in any copy made
X */
X
#include "tin.h"
X
extern char cvers[LEN];
extern int cur_groupnum;
extern int last_resp; /* page.c */
extern int this_resp; /* page.c */
X
char *glob_group;
int index_point;
int first_subj_on_screen;
int last_subj_on_screen;
X
X
void group_page (group)
X char *group;
{
#ifndef INDEX_DAEMON
X
X char group_path[LEN];
X char buf[32];
X char ch;
X char *p;
X int flag, i, n;
X int kill_state;
X int old_top;
X int posted;
X int sav_groupnum;
X int scroll_lines;
X long old_artnum;
X
X active[my_group[cur_groupnum]].read = TRUE;
X
X glob_group = group;
X sav_groupnum = cur_groupnum;
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
X last_resp = -1;
X this_resp = -1;
X index_group (group, group_path); /* update index file */
#if 0 /* JBR */
X read_newsrc_line (group); /* get sequencer information */
X
X if (show_only_unread) {
X make_threads (FALSE);
X find_base (show_only_unread);
X }
X
X debug_print_base ();
#endif
X
X if (space_mode) {
X for (i = 0; i < top_base; i++) {
X if (new_responses (i)) {
X break;
X }
X }
X if (i < top_base) {
X index_point = i;
X } else {
X index_point = top_base - 1;
X }
X } else {
X index_point = top_base - 1;
X }
X if (index_point < 0) {
X index_point = 0;
X }
X
X clear_note_area ();
X
X show_group_page (group);
X
X while (TRUE) {
X ch = (char) ReadCh ();
X
X if (ch > '0' && ch <= '9') { /* 0 goes to basenote */
X prompt_subject_num (ch, group);
X continue;
X }
X switch (ch) {
X case ESC: /* common arrow keys */
X switch (get_arrow_key ()) {
X case KEYMAP_UP:
X goto group_up;
X
X case KEYMAP_DOWN:
X goto group_down;
X
X case KEYMAP_PAGE_UP:
X goto group_page_up;
X
X case KEYMAP_PAGE_DOWN:
X goto group_page_down;
X
X case KEYMAP_HOME:
X if (index_point != 0) {
X index_point = 0;
X show_group_page (group);
X }
X break;
X
X case KEYMAP_END:
X goto end_of_list;
X }
X break;
X
#ifndef NO_SHELL_ESCAPE
X case '!':
X shell_escape ();
X show_group_page (group);
X break;
#endif
X
X case '$': /* show last page of articles */
end_of_list:
X if (index_point != top_base - 1) {
X index_point = top_base - 1;
X show_group_page (group);
X }
X break;
X
X case '-': /* go to last viewed article */
X if (this_resp < 0) {
X info_message (txt_no_last_message);
SHAR_EOF
true || echo 'restore of group.c failed'
fi
echo 'End of tin1.1 part 4'
echo 'File group.c is continued in part 5'
echo 5 > _shar_seq_.tmp
exit 0
--
NAME Iain Lea
EMAIL iain%anl433.uucp@germany.eu.net
SNAIL Siemens AG, ANL A433SZ, Gruendlacher Str. 248, 8510 Fuerth, Germany.
PHONE +49-911-3089-407 (work) +49-911-331963 (home) +49-911-3089-290 (FAX)
--
Dr. med. dipl.-math Dieter Becker Tel.: (0 / +49) 6841 - 16 3046
Medizinische Universitaets- und Poliklinik Fax.: (0 / +49) 6841 - 16 3369
Innere Medizin III
D - 6650 Homburg / Saar Email: becker@med-in.uni-sb.de
exit 0 # Just in case...