home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 January
/
usenetsourcesnewsgroupsinfomagicjanuary1994.iso
/
sources
/
misc
/
volume28
/
tin
/
part07
< prev
next >
Wrap
Text File
|
1992-02-23
|
52KB
|
2,331 lines
Newsgroups: comp.sources.misc
From: iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE (Iain Lea)
Subject: v28i051: tin - threaded full screen newsreader v1.1, Part07/11
Message-ID: <1992Feb18.043811.13229@sparky.imd.sterling.com>
X-Md4-Signature: 60c986a8347296f9f337b85b58ff1012
Date: Tue, 18 Feb 1992 04:38:11 GMT
Approved: kent@sparky.imd.sterling.com
Submitted-by: iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE (Iain Lea)
Posting-number: Volume 28, Issue 51
Archive-name: tin/part07
Environment: BSD, SCO, ISC, SUNOS, SYSVR3, SYSVR4, ULTRIX, XENIX
Supersedes: tin: Volume 23, Issue 15-23
#!/bin/sh
# this is tin.shar.07 (part 7 of tin1.1)
# do not concatenate these parts, unpack them in order with /bin/sh
# file newsrc.c continued
#
if test ! -r _shar_seq_.tmp; then
echo 'Please unpack part 1 first!'
exit 1
fi
(read Scheck
if test "$Scheck" != 7; 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 newsrc.c'
else
echo 'x - continuing file newsrc.c'
sed 's/^X//' << 'SHAR_EOF' >> 'newsrc.c' &&
X * the bottom, use it as the new bottom instead
X */
X
X high = 0;
X if (*s) {
X while (*s && (*s < '0' || *s > '9'))
X s++;
X
X if (*s && *s >= '0' && *s <= '9') {
X low = (long) atol (s);
X while (*s && *s >= '0' && *s <= '9')
X s++;
X if (*s == '-') {
X s++;
X high = (long) atol (s);
X while (*s && *s >= '0' && *s <= '9')
X s++;
X } else
X high = low;
X gotone = TRUE;
X }
X }
X
X if (high < active[groupnum].min)
X high = active[groupnum].min;
X
X while (*s) {
X last_high = high;
X
X while (*s && (*s < '0' || *s > '9'))
X s++;
X
X if (*s && *s >= '0' && *s <= '9') {
X low = (long) atol (s);
X while (*s && *s >= '0' && *s <= '9')
X s++;
X if (*s == '-') {
X s++;
X high = (long) atol (s);
X while (*s && *s >= '0' && *s <= '9')
X s++;
X } else
X high = low;
X
X if (low > last_high) /* otherwise seq out of order */
X sum += (low - last_high) - 1;
X }
X }
X
X if (gotone) {
X if (active[groupnum].max > high)
X sum += active[groupnum].max - high;
X return sum;
X }
X
X n = (int) (active[groupnum].max - active[groupnum].min);
X if (n < 2)
X return 0;
X
X return -1;
}
X
X
int get_line_unread(group, groupnum)
X char *group;
X int groupnum; /* index for group in active[] */
{
X FILE *fp;
X char buf[8192];
X char *p;
X int ret = -1;
X
X if ((fp = fopen(newsrc, "r")) == NULL)
X return -1;
X
X while (fgets(buf, sizeof (buf), fp) != NULL) {
X p = buf;
X while (*p && *p != '\n' && *p != ' ' && *p != ':' && *p != '!')
X p++;
X *p++ = '\0';
X
X if (strcmp (buf, group) != 0)
X continue;
X
X ret = parse_unread (p, groupnum);
X break;
X }
X
X fclose (fp);
X return ret;
}
X
X
void print_seq (fp, groupnum)
X FILE *fp;
X int groupnum; /* index into active[] for this group */
{
X int i;
X int flag = FALSE;
X
X if (top <= 0) {
X if (active[groupnum].min > 1) {
X fprintf (fp, "1-%ld", active[groupnum].min);
X fflush (fp);
X }
X return;
X }
X
X /*
X * sort into the same order as in the spool area for writing
X * read article numbers to ~/.newsrc
X */
X qsort ((char *) arts, top, sizeof (struct article_t), artnum_comp);
X
X i = 0;
X if (arts[0].artnum > 1) {
X for (; i < top && !arts[i].unread; i++)
X continue;
X if (i > 0)
X fprintf (fp, "1-%ld", arts[i-1].artnum);
X else
X fprintf (fp, "1-%ld", arts[0].artnum - 1);
X flag = TRUE;
X }
X
X for (; i < top; i++) {
X if (! arts[i].unread) {
X if (flag)
X fprintf(fp, ",");
X else
X flag = TRUE;
X fprintf (fp, "%ld", arts[i].artnum);
X if (i+1 < top && !arts[i+1].unread) {
X while (i+1 < top && ! arts[i+1].unread)
X i++;
X fprintf (fp, "-%ld", arts[i].artnum);
X }
X }
X }
X
X if (! flag && active[groupnum].min > 1)
X fprintf (fp, "1-%ld", active[groupnum].min);
X fflush (fp);
X
X /*
X * resort into required sort order
X */
X switch (sort_art_type) {
X case SORT_BY_NOTHING: /* already sorted above */
X break;
X case SORT_BY_SUBJ_DESCEND:
X case SORT_BY_SUBJ_ASCEND:
X qsort ((char *) arts, top, sizeof (struct article_t), subj_comp);
X break;
X case SORT_BY_FROM_DESCEND:
X case SORT_BY_FROM_ASCEND:
X qsort ((char *) arts, top, sizeof (struct article_t), from_comp);
X break;
X case SORT_BY_DATE_DESCEND:
X case SORT_BY_DATE_ASCEND:
X qsort ((char *) arts, top, sizeof (struct article_t), date_comp);
X break;
X }
}
X
/*
X * rewrite .newsrc and position group at specifed position
X */
X
int pos_group_in_newsrc (group, pos)
X char *group;
X int pos;
{
X char sub[1024];
X char unsub[1024];
X char buf[1024];
X char newsgroup[1024];
X extern int cur_groupnum;
X FILE *fp_in, *fp_out;
X FILE *fp_sub, *fp_unsub;
X int repositioned = FALSE;
X int subscribed_pos = 1;
X int group_len;
X int option_line = FALSE;
X int ret_code = FALSE;
X
X set_real_uid_gid ();
X
X if ((fp_in = fopen (newsrc, "r")) == NULL) {
X goto rewrite_group_done;
X }
X if ((fp_out = fopen (newnewsrc, "w")) == NULL) {
X goto rewrite_group_done;
X }
X
X sprintf (sub, "/tmp/.subrc.%d", getpid ());
X sprintf (unsub, "/tmp/.unsubrc.%d", getpid ());
X
X if ((fp_sub = fopen (sub, "w")) == NULL) {
X goto rewrite_group_done;
X }
X if ((fp_unsub = fopen (unsub, "w")) == NULL) {
X goto rewrite_group_done;
X }
X
X /*
X * split newsrc into subscribed and unsubscribed to files
X */
X group_len = strlen (group);
X
X while (fgets (buf, sizeof (buf), fp_in) != NULL) {
X if (strncmp (group, buf, group_len) == 0 && buf[group_len] == ':') {
X my_strncpy (newsgroup, buf, LEN);
X } else if (strchr (buf, ':') != NULL) {
X fprintf (fp_sub, "%s", buf);
X } else if (strchr (buf, '!') != NULL) {
X fprintf (fp_unsub, "%s", buf);
X } else { /* options line at beginning of .newsrc */
X fprintf (fp_sub, "%s", buf);
X option_line = TRUE;
X }
X }
X
X fclose (fp_in);
X fclose (fp_sub);
X fclose (fp_unsub);
X
X /*
X * write subscribed groups & position group to newnewsrc
X */
X if ((fp_sub = fopen (sub, "r")) == NULL) {
X unlink (sub);
X goto rewrite_group_done;
X }
X while (fgets (buf, LEN, fp_sub) != NULL) {
X if (option_line) {
X if (strchr (buf, ':') == NULL && strchr (buf, '!') == NULL) {
X fprintf (fp_out, "%s", buf);
X continue;
X } else {
X option_line = FALSE;
X }
X }
X
X if (pos == subscribed_pos) {
X fprintf (fp_out, "%s\n", newsgroup);
X repositioned = TRUE;
X }
X
X fprintf (fp_out, "%s", buf);
X
X subscribed_pos++;
X }
X if (! repositioned) {
X fprintf (fp_out, "%s\n", newsgroup);
X repositioned = TRUE;
X }
X
X fclose (fp_sub);
X unlink (sub);
X
X /*
X * write unsubscribed groups to newnewsrc
X */
X if ((fp_unsub = fopen (unsub, "r")) == NULL) {
X unlink (unsub);
X goto rewrite_group_done;
X }
X while (fgets (buf, LEN, fp_unsub) != NULL) {
X fprintf (fp_out, "%s", buf);
X }
X
X fclose (fp_unsub);
X unlink (unsub);
X fclose (fp_out);
X
X if (repositioned) {
X cur_groupnum = pos;
X rename_file (newnewsrc, newsrc);
X ret_code = TRUE;
X }
X
rewrite_group_done:
X set_tin_uid_gid ();
X return ret_code;
}
X
/*
X * mark all orther Xref: articles as read when one article read
X * Xref: sitename newsgroup:artnum newsgroup:artnum [newsgroup:artnum ...]
X */
X
void mark_all_xref_read (xref_line)
X char *xref_line;
{
X char group[LEN];
X long artnum;
X
X if (xref_line == (char *) 0) {
X return;
X }
X
X /*
X * check sitename macthes nodename of current machine
X */
X
X /*
X * tokenize each pair and update that newsgroup if it
X * is in users my_group[].
X */
X
}
SHAR_EOF
echo 'File newsrc.c is complete' &&
chmod 0600 newsrc.c ||
echo 'restore of newsrc.c failed'
Wc_c="`wc -c < 'newsrc.c'`"
test 19837 -eq "$Wc_c" ||
echo 'newsrc.c: original size 19837, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= open.c ==============
if test -f 'open.c' -a X"$1" != X"-c"; then
echo 'x - skipping open.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting open.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'open.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : open.c
X * Author : R.Skrenta / I.Lea
X * Created : 01-04-91
X * Updated : 08-02-92
X * Notes : reads news locally (ie. /usr/spool/news) or via NNTP
X * Copyright : (c) Copyright 1991-92 by Rich Skrenta & 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"
#ifdef USE_NNTP
# include "nntp.h"
#endif
X
/* Hopefully one of these is right for you. */
X
#ifdef BSD
# ifdef SINIX
# include <dir.h>
# else
# include <sys/dir.h>
# endif
# 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
# ifdef sorix960
# include <sys/dirent.h>
# else
# include <dirent.h>
# endif
# define DIR_BUF struct dirent
# define D_LENGTH d_reclen
#endif
X
#ifdef USE_NNTP
int compiled_with_nntp = TRUE; /* used in mail_bug_report() info */
#else
int compiled_with_nntp = FALSE;
#endif
X
#ifdef NO_POSTING
int can_post = FALSE;
#else
int can_post = TRUE;
#endif
X
char server_name[LEN];
X
X
char *is_remote ()
{
X server_name[0] = '\0';
X
#ifdef USE_NNTP
X if (read_news_via_nntp) {
X if (nntp_server[0]) {
X sprintf (server_name, " (%s)", nntp_server);
X } else {
X if (getserverbyfile (NNTP_SERVER_FILE)) {
X sprintf (server_name, " (%s)", getserverbyfile (NNTP_SERVER_FILE));
X } else {
X strcpy (server_name, " (NO SERVER)");
X }
X }
X }
#endif
X
X return (server_name);
}
X
X
void nntp_startup ()
{
#ifdef USE_NNTP
X char *server;
X int ret;
X extern char *getenv();
X
X if (read_news_via_nntp) {
X if (nntp_server[0]) {
X server = nntp_server;
X } else {
X server = getserverbyfile (NNTP_SERVER_FILE);
X }
X if (server == (char *) 0) {
X fprintf (stderr, txt_cannot_get_nntp_server_name);
X fprintf (stderr, txt_server_name_in_file_env_var, NNTP_SERVER_FILE);
X exit(1);
X }
X
X if (update == FALSE) {
X printf (txt_connecting, server);
X fflush (stdout);
X }
X
X ret = server_init (server);
X if (update == FALSE) {
X putchar ('\n');
X }
/*
X handle_server_response (ret, server);
*/
X switch (ret) {
X case OK_CANPOST:
#ifndef NO_POSTING
X can_post = TRUE;
#endif
X break;
X
X case OK_NOPOST:
X can_post = FALSE;
X break;
X
X case -1:
X fprintf (stderr, txt_failed_to_connect_to_server, server);
X exit (1);
X
X default:
X fprintf (stderr, txt_rejected_by_nntpserver, ret);
X exit (1);
X }
X }
#endif
}
X
X
void nntp_finish ()
{
#ifdef USE_NNTP
X if (read_news_via_nntp) {
X close_server ();
X }
#endif
}
X
X
FILE *open_active_fp ()
{
X if (read_news_via_nntp) {
#ifdef USE_NNTP
X put_server ("list");
X if (get_respcode () != OK_GROUPS) {
X return NULL;
X }
X return nntp_to_fp ();
#else
X return NULL;
#endif
X } else {
X return fopen (active_file, "r");
X }
}
X
X
FILE *open_art_fp (group_path, art)
X char *group_path;
X long art;
{
X char buf[LEN];
X int respcode;
X struct stat sb;
X extern long note_size;
X
X if (read_news_via_nntp) {
#ifdef USE_NNTP
X sprintf (buf, "article %ld", art);
X
X put_server (buf);
X if ((respcode = get_respcode ()) != OK_ARTICLE) {
X sprintf (msg, "Cannot open art on NNTP server. Respcode %d", respcode);
X error_message (msg);
X return (FILE *) 0;
X }
X
X return nntp_to_fp ();
#else
X return (FILE *) 0;
#endif
X } else {
X sprintf (buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
X
X if (stat (buf, &sb) < 0) {
X note_size = 0;
X } else {
X note_size = sb.st_size;
X }
X return fopen (buf, "r");
X }
}
X
X
int open_header_fd (group_path, art)
X char *group_path;
X long art;
{
X char buf[LEN];
X
X if (read_news_via_nntp) {
#ifdef USE_NNTP
X sprintf(buf, "head %ld", art);
X
X put_server (buf);
X if (get_respcode () != OK_HEAD) {
X return -1;
X }
X
X return nntp_to_fd ();
#else
X return -1;
#endif
X } else {
X sprintf (buf, "%s/%s/%ld", SPOOLDIR, group_path, art);
X return open (buf, 0);
X }
}
X
/*
X * Longword comparison routine for the qsort()
X */
X
int base_comp (p1, p2)
X char *p1;
X char *p2;
{
X long *a = (long *) p1;
X long *b = (long *) p2;
X
X if (*a < *b)
X return -1;
X if (*a > *b)
X return 1;
X return 0;
}
X
X
/*
X * Read the article numbers existing in a group's spool directory
X * into base[] and sort them. top_base is one past top.
X */
X
void setup_base (group, group_path)
X char *group;
X char *group_path;
{
X char buf[LEN];
#ifdef USE_NNTP
X char line[NNTP_STRLEN];
#endif
X DIR *d;
X DIR_BUF *e;
X long art, start, last, dummy, count;
X
X top_base = 0;
X
X if (read_news_via_nntp) {
#ifdef USE_NNTP
X sprintf (buf, "group %s", group);
X put_server (buf);
X
X if (get_server (line, NNTP_STRLEN) == -1) {
X fprintf (stderr, txt_connection_to_server_broken);
X tin_done (1);
X }
X
X if (atoi(line) != OK_GROUP) {
X return;
X }
X
X sscanf (line,"%ld %ld %ld %ld", &dummy, &count, &start, &last);
X if (last - count > start) {
X start = last - count;
X }
X
X while (start <= last) {
X if (top_base >= max_art) {
X expand_art();
X }
X base[top_base++] = start++;
X }
#else
X return;
#endif
X } else {
X sprintf (buf, "%s/%s", SPOOLDIR, group_path);
X
X if (access (buf, 4) != 0) {
X return;
X }
X
X d = opendir (buf);
X if (d != NULL) {
X while ((e = readdir (d)) != NULL) {
X art = my_atol (e->d_name, (int) e->D_LENGTH);
X if (art >= 0) {
X if (top_base >= max_art)
X expand_art ();
X base[top_base++] = art;
X }
X }
X closedir (d);
X qsort ((char *) base, top_base, sizeof (long), base_comp);
X }
X }
}
X
/*
X * get_respcode
X * get a response code from the server and return it to the caller
X */
X
int get_respcode ()
{
#ifdef USE_NNTP
X char line[NNTP_STRLEN];
X
X if (get_server (line, NNTP_STRLEN) == -1) {
X fprintf (stderr, txt_connection_to_server_broken);
X tin_done (1);
X }
X
X return atoi (line);
#endif
}
X
X
int stuff_nntp (fnam)
X char *fnam;
{
#ifdef USE_NNTP
X FILE *fp;
X char line[NNTP_STRLEN];
X extern char *mktemp();
X struct stat sb;
X extern long note_size;
X
X strcpy(fnam, "/tmp/tin_nntpXXXXXX");
X mktemp(fnam);
X
X if ((fp = fopen(fnam, "w")) == NULL) {
X error_message (txt_stuff_nntp_cannot_open, fnam);
X return FALSE;
X }
X
X while (1) {
X if (get_server(line, NNTP_STRLEN) == -1) {
X fprintf(stderr, txt_connection_to_server_broken);
X tin_done (1);
X }
X if (strcmp(line, ".") == 0)
X break; /* end of text */
X strcat(line, "\n");
X if (line[0] == '.') /* reduce leading .'s */
X fputs(&line[1], fp);
X else
X fputs(line, fp);
X }
X fclose(fp);
X
X if (stat(fnam, &sb) < 0)
X note_size = 0;
X else
X note_size = sb.st_size;
X
X return TRUE;
#else
X return TRUE;
#endif
}
X
X
FILE *nntp_to_fp ()
{
#ifdef USE_NNTP
X char fnam[LEN];
X static FILE *fp = NULL;
X
X if (fp != NULL) {
X fclose (fp);
X }
X
X if (! stuff_nntp (fnam)) {
X return NULL;
X }
X
X if ((fp = fopen (fnam, "r")) == NULL) {
X error_message (txt_nntp_to_fp_cannot_reopen, fnam);
X return NULL;
X }
X
X unlink (fnam);
X return fp;
#else
X return NULL;
#endif
}
X
X
int nntp_to_fd ()
{
#ifdef USE_NNTP
X char fnam[LEN];
X static int fd = -1;
X
X if (fd != -1) {
X close (fd);
X }
X
X if (! stuff_nntp (fnam)) {
X return -1;
X }
X
X if ((fd = open (fnam, 0)) == -1) {
X error_message (txt_nntp_to_fd_cannot_reopen, fnam);
X return -1;
X }
X
X unlink (fnam);
X return fd;
#else
X return -1;
#endif
}
SHAR_EOF
chmod 0600 open.c ||
echo 'restore of open.c failed'
Wc_c="`wc -c < 'open.c'`"
test 7366 -eq "$Wc_c" ||
echo 'open.c: original size 7366, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= page.c ==============
if test -f 'page.c' -a X"$1" != X"-c"; then
echo 'x - skipping page.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting page.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'page.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : page.c
X * Author : R.Skrenta / I.Lea
X * Created : 01-04-91
X * Updated : 30-01-92
X * Notes :
X * Copyright : (c) Copyright 1991-92 by Rich Skrenta & 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
#define ART_UNAVAILABLE -1
X
extern int cur_groupnum;
X
char note_h_path[LEN]; /* Path: */
char note_h_date[LEN]; /* Date: */
char note_h_subj[LEN]; /* Subject: */
char note_h_org[LEN]; /* Organization: */
char note_h_newsgroups[LEN]; /* Newsgroups: */
char note_h_messageid[LEN]; /* Message-ID: */
char note_h_distrib[LEN]; /* Distribution: */
char note_h_followup[LEN]; /* Followup-To: */
X
char *glob_page_group;
X
FILE *note_fp; /* the body of the current article */
X
int glob_respnum;
int last_resp; /* current & previous article for - command */
int note_end; /* we're done showing this article */
int note_line;
int note_page; /* what page we're on */
int rotate; /* 0=normal, 13=rot13 decode */
int this_resp;
X
long note_mark[MAX_PAGES]; /* ftells on beginnings of pages */
long note_size; /* stat size in bytes of article */
X
X
int show_page (respnum, group, group_path)
X int respnum;
X char *group;
X char *group_path;
{
X char ch;
X int i, n;
X int kill_state = NO_KILLING;
X int old_sort_art_type = sort_art_type;
X int old_top;
X int posted;
X int ret_code;
X long old_artnum;
X long art;
X
restart:
X
X glob_respnum = respnum;
X glob_page_group = group;
X
X set_signals_page ();
X
X if (respnum != this_resp) { /* remember current & previous */
X last_resp = this_resp; /* articles for - command */
X this_resp = respnum;
X }
X
X rotate = 0; /* normal mode, not rot13 */
X art = arts[respnum].artnum;
X arts[respnum].unread = ART_READ; /* mark article as read */
X art_open (art, group_path);
X
X if (note_page == ART_UNAVAILABLE) {
X ClearScreen ();
X printf (txt_art_unavailable, art);
X fflush (stdout);
X } else {
X show_note_page (respnum, group);
X }
X
X while (TRUE) {
X ch = (char) ReadCh();
X
X if (ch >= '0' && ch <= '9') {
X
X n = prompt_response (ch, respnum);
X if (n != -1) {
X respnum = n;
X goto restart;
X }
X
X } else switch (ch) {
X case ESC:
X switch (get_arrow_key ()) {
X case KEYMAP_PAGE_UP:
X goto page_up;
X
X case KEYMAP_PAGE_DOWN:
X goto page_down;
X
X case KEYMAP_HOME:
X goto begin_of_article;
X
X case KEYMAP_END:
X goto end_of_article;
X }
X break;
X
#ifndef NO_SHELL_ESCAPE
X case '!':
X shell_escape ();
X redraw_page (respnum, group);
X break;
#endif
X
X case '$': /* goto end of article */
X case 'G': /* 'less' compatible */
end_of_article:
X if (show_last_page ()) {
X show_note_page (respnum, group);
X }
X break;
X
X case '-': /* show last viewed article */
X if (last_resp < 0) {
X info_message(txt_no_last_message);
X break;
X }
X art_close();
X respnum = last_resp;
X goto restart;
X
X case '|': /* pipe article/thread/tagged arts to command */
X set_real_uid_gid ();
X feed_articles (FEED_PIPE, PAGE_LEVEL, "Pipe", respnum, group_path);
X set_tin_uid_gid ();
X break;
X
X case '/': /* search forwards in article */
X if (search_article (TRUE)) {
X show_note_page (respnum, group);
X }
X break;
X
X case '<': /* goto first article in current thread */
X if (arts[respnum].inthread) {
X n = which_thread (respnum);
X if (n != respnum && n >= 0) {
X respnum = n;
X art_close ();
X goto restart;
X }
X }
X break;
X
X case '>': /* goto last article in current thread */
X for (i = respnum; i >= 0; i = arts[i].thread) {
X n = i;
X }
X if (n != respnum) {
X respnum = n;
X art_close ();
X goto restart;
X }
X break;
X
X case ' ': /* next page or response */
X case ctrl('D'): /* vi style */
X case ctrl('V'): /* emacs style */
page_down:
X if (note_page == ART_UNAVAILABLE) {
X n = next_response (respnum);
X if (n == -1) {
X return (which_thread (respnum));
X }
X respnum = n;
X goto restart;
X } else if (note_end) {
X art_close ();
X n = next_response (respnum);
X if (n == -1) {
X return (which_thread (respnum));
X }
X respnum = n;
X goto restart;
X } else
X show_note_page (respnum, group);
X break;
X
X case '\r':
X case '\n': /* go to start of next thread */
X art_close ();
X n = next_thread (respnum);
X if (n == -1)
X return (which_thread (respnum));
X
X respnum = n;
X goto restart;
X
X case '\t': /* goto next unread article */
X if (note_page != ART_UNAVAILABLE) {
X art_close();
X }
X n = next_unread (next_response (respnum));
X if (n == -1) {
X return (which_thread (respnum));
X }
X respnum = n;
X goto restart;
X break;
X
X case ctrl('H'): /* show article headers */
X if (note_page == ART_UNAVAILABLE) {
X n = next_response (respnum);
X if (n == -1)
X return (which_thread (respnum));
X
X respnum = n;
X goto restart;
X } else {
X note_page = 0;
X note_end = FALSE;
X fseek(note_fp, 0L, 0);
X show_note_page(respnum, group);
X }
X break;
X
X case ctrl('K'): /* kill article */
X if (kill_articles) {
X if (kill_art_menu (group, respnum)) {
X if (kill_any_articles (group)) {
X reload_index_file (group, TRUE);
X }
X }
X redraw_page(respnum, group);
X } else {
X info_message (txt_switch_on_kill_art_menu);
X }
X break;
X
X case ctrl('L'): /* redraw current page of article */
X redraw_page (respnum, group);
X break;
X
X case ctrl('R'): /* redraw beginning of article */
X case 'g': /* 'less' compatible */
begin_of_article:
X if (note_page == ART_UNAVAILABLE) {
X ClearScreen ();
X printf (txt_art_unavailable,arts[respnum].artnum);
X fflush (stdout);
X } else {
X note_page = 0;
X note_end = FALSE;
X fseek (note_fp, note_mark[0], 0);
X show_note_page (respnum, group);
X }
X break;
X
X case ctrl('X'):
X case '%':
X case 'd': /* toggle rot-13 mode */
X if (rotate)
X rotate = 0;
X else
X rotate = 13;
X redraw_page (respnum, group);
X info_message (txt_toggled_rot13);
X break;
X
X case 'a': /* author search forward */
X case 'A': /* author search backward */
X i = (ch == 'a');
X n = search_author (top, respnum, i);
X if (n < 0)
X break;
X respnum = n;
X goto restart;
X /* NOTREACHED */
X
X case ctrl('U'):
X case 'b': /* back a page */
page_up:
X if (note_page == ART_UNAVAILABLE) {
X art_close();
X n = prev_response (respnum);
X if (n == -1)
X return (which_response (respnum));
X
X respnum = n;
X goto restart;
X
X } else {
X if (note_page <= 1) {
X info_message (txt_begin_of_art);
X } else {
X note_page -= 2;
X note_end = FALSE;
X fseek (note_fp, note_mark[note_page], 0);
X show_note_page (respnum, group);
X }
X }
X break;
X
X case 'B': /* bug/gripe/comment mailed to author */
X mail_bug_report ();
X redraw_page (respnum, group);
X break;
X
X case 'c': /* catchup--mark all articles as read */
X if (prompt_yn (LINES, txt_mark_all_read, 'y')) {
X for (n = 0; n < top; n++) {
X arts[n].unread = ART_READ;
X }
X fix_new_highest(cur_groupnum);
X if (cur_groupnum + 1 < group_top) {
X cur_groupnum++;
X }
X art_close();
X return -1;
X }
X break;
X
X case 'C': /* cancel an article */
X if (cancel_article ()) {
X redraw_page (respnum, group);
X }
X break;
X
X case 'f': /* post a followup to this article */
X if (! can_post) {
X info_message (txt_cannot_post);
X break;
X }
X ret_code = post_response (group, respnum, FALSE);
X if (ret_code >= POSTED_REDRAW) {
X update_newsrc (group, my_group[cur_groupnum], FALSE);
X if (ret_code == POSTED_OK) {
X n = which_thread (respnum);
X art_close ();
X index_group (group, group_path);
X read_newsrc_line (group);
X respnum = choose_response (n, num_of_responses (n));
X goto restart;
X } else {
X redraw_page (respnum, group);
X }
X } else {
X redraw_page (respnum, group);
X }
X break;
X
X case 'F': /* post a followup to this article */
X if (! can_post) {
X info_message (txt_cannot_post);
X break;
X }
X ret_code = post_response (group, respnum, TRUE);
X
X if (ret_code >= POSTED_REDRAW) {
X update_newsrc (group, my_group[cur_groupnum], FALSE);
X if (ret_code == POSTED_OK) {
X n = which_thread (respnum);
X art_close ();
X index_group (group, group_path);
X read_newsrc_line (group);
X respnum = choose_response (n, num_of_responses (n));
X goto restart;
X } else {
X redraw_page (respnum, group);
X }
X } else {
X redraw_page (respnum, group);
X }
X break;
X
X case 'h': /* help */
X show_info_page (HELP_INFO, help_page, txt_art_pager_com);
X redraw_page (respnum, group);
X break;
X
X case 'i': /* return to index page */
return_to_index:
X art_close ();
X if (kill_state == NO_KILLING &&
X sort_art_type != old_sort_art_type) {
X make_threads (TRUE);
X find_base (show_only_unread);
X }
X if (kill_state == KILLING) {
X old_top = top;
X old_artnum = arts[respnum].artnum;
X if (kill_articles) {
X kill_any_articles (group);
X reload_index_file (group, TRUE); /* kill arts */
X } else {
X reload_index_file (group, FALSE); /* unkill arts */
X }
X return find_new_pos (old_top, old_artnum, respnum);
X }
X return (which_thread (respnum));
X
X case 'I': /* toggle inverse video */
X toggle_inverse_video ();
X redraw_page (respnum, group);
X break;
X
X case 'k':
X if (note_page == ART_UNAVAILABLE) {
X n = next_unread (next_response(respnum));
X if (n == -1)
X return (which_thread (respnum));
X } else {
X art_close ();
X n = next_unread (next_response (respnum));
X if (n == -1)
X return (which_thread (respnum));
X }
X respnum = n;
X goto restart;
X /* NOTREACHED */
X
X case 'K': /* mark rest of thread as read */
X for (n = respnum; n >= 0; n = arts[n].thread)
X arts[n].unread = ART_READ;
X n = next_unread (next_response (respnum));
X if (n == -1)
X goto return_to_index;
X art_close ();
X respnum = n;
X goto restart;
X /* NOTREACHED */
#ifdef NYI
X case 'l': /* list articles within current thread */
X if (show_thread (respnum, group, group_path)) {
X redraw_page (respnum, group);
X }
X break;
#endif
X
X case 'm': /* mail article/thread/tagged articles to somebody */
X set_real_uid_gid ();
X feed_articles (FEED_MAIL, PAGE_LEVEL, "Mail", respnum, group_path);
X set_tin_uid_gid ();
X break;
X
X case 'M': /* options menu */
X if (change_rcfile (group, FALSE) == KILLING) {
X kill_state = KILLING;
X }
X redraw_page (respnum, group);
X break;
X
X case 'n': /* skip to next article */
X art_close ();
X n = next_response (respnum);
X if (n == -1)
X return (which_thread(respnum));
X
X respnum = n;
X goto restart;
X /* NOTREACHED */
X
X case 'N': /* next unread article */
X n = next_unread(next_response(respnum));
X if (n == -1)
X info_message(txt_no_next_unread_art);
X else {
X art_close();
X respnum = n;
X goto restart;
X }
X break;
X
X case 'o': /* output art/thread/tagged arts to printer */
X set_real_uid_gid ();
X feed_articles (FEED_PRINT, PAGE_LEVEL, "Print", respnum, group_path);
X set_tin_uid_gid ();
X break;
X
X case 'p': /* previous article */
X art_close ();
X n = prev_response (respnum);
X if (n == -1)
X return (which_response (respnum));
X
X respnum = n;
X goto restart;
X
X case 'P': /* previous unread article */
X n = prev_unread (prev_response (respnum));
X if (n == -1)
X info_message (txt_no_prev_unread_art);
X else {
X art_close ();
X respnum = n;
X goto restart;
X }
X break;
X
X case 'q': /* quit */
X if (prompt_yn (LINES, txt_quit, 'y')) {
X return -2;
X }
X break;
X
X case 'r': /* reply to author through mail */
X mail_to_author (respnum, FALSE);
X redraw_page (respnum, group);
X break;
X
X case 'R': /* reply to author, copy text */
X mail_to_author (respnum, TRUE);
X redraw_page (respnum, group);
X break;
X
X case 's': /* save article/thread/tagged articles */
X set_real_uid_gid ();
X feed_articles (FEED_SAVE, PAGE_LEVEL, "Save", respnum, group_path);
X set_tin_uid_gid ();
X break;
X
X case 't': /* return to group selection page */
X art_close ();
X if (kill_state == KILLING) {
X if (kill_articles) {
X kill_any_articles (group);
X reload_index_file (group, TRUE); /* kill arts */
X } else {
X reload_index_file (group, FALSE); /* unkill arts */
X }
X }
X update_newsrc (group, my_group[cur_groupnum], FALSE);
X fix_new_highest (cur_groupnum);
X return -1;
X
X case 'T': /* tag/untag article for saving */
X if (arts[respnum].tagged) {
X arts[respnum].tagged = 0;
X info_message (txt_untagged_art);
X } else {
X arts[respnum].tagged = ++num_of_tagged_files;
X info_message (txt_tagged_art);
X }
X break;
X
X case 'v':
X info_message (cvers);
X break;
X
X case 'w': /* post a basenote */
X if (! can_post) {
X info_message (txt_cannot_post);
X break;
X }
X if (post_base (group, &posted)) {
X if (posted) {
X update_newsrc (group, my_group[cur_groupnum], FALSE);
X index_group (group, group_path);
X read_newsrc_line (group);
X }
X redraw_page (respnum, group);
X }
X break;
X
X case 'W': /* display messages posted by user */
X if (user_posted_messages ()) {
X redraw_page (respnum, group);
X }
X break;
X
X case 'z': /* mark article as unread (to return) */
X arts[respnum].unread = ART_WILL_RETURN;
X info_message (txt_art_marked_as_unread);
X break;
X
X default:
X info_message(txt_bad_command);
X }
X }
}
X
X
void redraw_page (respnum, group)
X int respnum;
X char *group;
{
X
X if (note_page == ART_UNAVAILABLE) {
X ClearScreen ();
X printf (txt_art_unavailable, arts[respnum].artnum);
X fflush (stdout);
X } else if (note_page > 0) {
X note_page--;
X fseek (note_fp, note_mark[note_page], 0);
X show_note_page (respnum, group);
X }
}
X
X
void show_note_page (respnum, group)
X int respnum;
X char *group;
{
X char buf[LEN];
X char buf2[LEN+50];
X char *p, *q;
X int i, j;
X int ctrl_L; /* form feed character detected */
X long tmp_pos;
X
X ClearScreen ();
X
X note_line = 1;
X
X if (note_size == 0L) {
X tmp_pos = ftell (note_fp);
X fseek (note_fp, 0L, 2); /* goto end of article */
X note_size = ftell (note_fp);
X fseek (note_fp, tmp_pos, 0); /* goto old position */
X }
X
X if (note_page == 0)
X show_first_header (respnum, group);
X else
X show_cont_header (respnum);
X
X ctrl_L = FALSE;
X while (note_line < LINES) {
X if (fgets (buf, sizeof (buf), note_fp) == NULL) {
X note_end = TRUE;
X break;
X }
X
X buf[LEN-1] = '\0';
X if (rotate)
X for (p = buf, q = buf2; *p && *p != '\n' && q < &buf2[LEN]; p++) {
X if (*p == '\b' && q > buf2) {
X q--;
X } else if (*p == 12) { /* ^L */
X *q++ = '^';
X *q++ = 'L';
X ctrl_L = TRUE;
X } else if (*p == '\t') {
X i = q - buf2;
X j = (i|7) + 1;
X
X while (i++ < j)
X *q++ = ' ';
X } else if (((*p) & 0xFF) < ' ') {
X *q++ = '^';
X *q++ = ((*p) & 0xFF) + '@';
X } else if (*p >= 'A' && *p <= 'Z')
X *q++ = 'A' + (*p - 'A' + rotate) % 26;
X else if (*p >= 'a' && *p <= 'z')
X *q++ = 'a' + (*p - 'a' + rotate) % 26;
X else
X *q++ = *p;
X }
X else
X for (p = buf, q = buf2; *p && *p != '\n' && q < &buf2[LEN]; p++) {
X if (*p == '\b' && q > buf2) {
X q--;
X } else if (*p == 12) { /* ^L */
X *q++ = '^';
X *q++ = 'L';
X ctrl_L = TRUE;
X } else if (*p == '\t') {
X i = q - buf2;
X j = (i|7) + 1;
X
X while (i++ < j)
X *q++ = ' ';
X } else if (((*p) & 0xFF) < ' ') {
X *q++ = '^';
X *q++ = ((*p) & 0xFF) + '@';
X } else
X *q++ = *p;
X }
X
X *q = '\0';
X
X printf("%s\r\n", buf2);
X
X note_line += ((int) strlen (buf2) / COLS) + 1;
X
X if (ctrl_L) {
X break;
X }
X }
X
X note_mark[++note_page] = ftell (note_fp);
X
X if (note_mark[note_page] == note_size) {
X note_end = TRUE;
X }
X
X if (note_end) {
X MoveCursor (LINES, MORE_POS-(5+BLANK_PAGE_COLS));
X StartInverse ();
X if (arts[respnum].thread != -1) {
X printf (txt_next_resp);
X fflush (stdout);
X } else {
X printf (txt_last_resp);
X fflush (stdout);
X }
X EndInverse ();
X } else {
X if (note_size > 0) {
X draw_percent_mark ((int) note_mark[note_page], (int) note_size);
X } else {
X MoveCursor (LINES, MORE_POS-BLANK_PAGE_COLS);
X StartInverse ();
X printf (txt_more);
X fflush (stdout);
X EndInverse ();
X }
X }
X MoveCursor (LINES, 0);
}
X
X
void show_first_header (respnum, group)
X int respnum;
X char *group;
{
X int whichresp;
X int x_resp;
X char buf[LEN];
X char tmp[LEN];
X int pos, i;
X int n;
X
X whichresp = which_response (respnum);
X x_resp = num_of_responses (which_thread (respnum));
X
X ClearScreen ();
X
X strcpy (buf, note_h_date);
X pos = (COLS - (int) strlen (group)) / 2;
X for (i = strlen(buf); i < pos; i++)
X buf[i] = ' ';
X buf[i] = '\0';
X
X strcat (buf, group);
X
X for (i = strlen(buf); i < RIGHT_POS ; i++)
X buf[i] = ' ';
X buf[i] = '\0';
X
X printf (txt_thread_x_of_n, buf, which_thread (respnum) + 1, top_base);
X
X sprintf (buf, txt_art, arts[respnum].artnum);
X n = strlen (buf);
X fputs (buf, stdout);
X
X strcpy (buf, note_h_subj);
X buf[RIGHT_POS - 5 - n] = '\0';
X
X pos = ((COLS - (int) strlen (buf)) / 2) - 2;
X
X if (pos > n) {
X MoveCursor (1, pos);
X } else {
X MoveCursor (1, n);
X }
X
X StartInverse ();
X fputs (buf, stdout);
X EndInverse ();
X
X MoveCursor (1, RIGHT_POS);
X if (whichresp)
X printf (txt_resp_x_of_n, whichresp, x_resp);
X else {
X if (x_resp == 0)
X printf (txt_no_resp);
X else if (x_resp == 1)
X printf (txt_1_resp);
X else
X printf (txt_x_resp, x_resp);
X }
X
X if (*note_h_org) {
X if (strcmp (arts[respnum].from, arts[respnum].name) == 0) {
X strcpy (tmp, note_h_org);
X } else {
X sprintf (tmp, txt_s_at_s, arts[respnum].name, note_h_org);
X }
X } else {
X strcpy (tmp, arts[respnum].name);
X }
X
X tmp[LEN-1] = '\0';
X
X sprintf (buf, "%s ", arts[respnum].from);
X
X pos = COLS - 1 - (int) strlen(tmp);
X if ((int) strlen (buf) + (int) strlen (tmp) >= COLS - 1) {
X strncat (buf, tmp, COLS - 1 - (int) strlen(buf));
X buf[COLS-1] = '\0';
X } else {
X for (i = strlen(buf); i < pos; i++)
X buf[i] = ' ';
X buf[i] = '\0';
X strcat (buf, tmp);
X }
X printf ("%s\r\n\r\n", buf);
X
X note_line += 4;
}
X
X
void show_cont_header (respnum)
X int respnum;
{
X int whichresp;
X int whichbase;
X char buf[LEN];
X
X whichresp = which_response (respnum);
X whichbase = which_thread (respnum);
X
X assert (whichbase < top_base);
X
X if (whichresp)
X sprintf(buf, txt_thread_resp_page,
X whichbase + 1,
X top_base,
X whichresp,
X note_page + 1,
X note_h_subj);
X else
X sprintf(buf, txt_thread_page,
X whichbase + 1,
X top_base,
X note_page + 1,
X note_h_subj);
X
X buf[COLS-1] = '\0';
X printf("%s\r\n\r\n", buf);
X
X note_line += 2;
}
X
X
void art_open (art, group_path)
X long art;
X char *group_path;
{
X char buf[1025];
X char *p;
X
X note_page = 0;
X
X art_close (); /* just in case */
X
X if ((note_fp = open_art_fp (group_path, art)) == NULL) {
X error_message ("art %d not opened", "");
X note_page = ART_UNAVAILABLE;
X return;
X }
X
X note_h_path[0] = '\0';
X note_h_subj[0] = '\0';
X note_h_org[0] = '\0';
X note_h_date[0] = '\0';
X note_h_newsgroups[0] = '\0';
X note_h_messageid[0] = '\0';
X note_h_distrib[0] = '\0';
X note_h_followup[0] = '\0';
X
X while (fgets(buf, sizeof buf, note_fp) != NULL) {
X buf[1024] = '\0';
X
X for (p=buf ; *p && *p != '\n' ; p++) {
X if (((*p) & 0xFF) < ' ')
X *p = ' ';
X }
X *p = '\0';
X
X if (*buf == '\0')
X break;
X
X if (match_header (buf, "Path", note_h_path, LEN))
X continue;
X if (match_header (buf, "Subject", note_h_subj, LEN))
X continue;
X if (match_header (buf, "Organization", note_h_org, LEN))
X continue;
X if (match_header (buf, "Date", note_h_date, LEN))
X continue;
X if (match_header (buf, "Newsgroups", note_h_newsgroups, LEN))
X continue;
X if (match_header (buf, "Message-ID", note_h_messageid, LEN))
X continue;
X if (match_header (buf, "Message-Id", note_h_messageid, LEN))
X continue;
X if (match_header (buf, "Distribution", note_h_distrib, LEN))
X continue;
X if (match_header (buf, "Followup-To", note_h_followup, LEN))
X continue;
X }
X
X note_page = 0;
X note_mark[0] = ftell (note_fp);
X note_end = FALSE;
X
X return;
}
X
X
void art_close ()
{
X if (note_fp && note_page != ART_UNAVAILABLE) {
X fclose (note_fp);
X note_fp = (FILE *) 0;
X }
}
X
X
int prompt_response (ch, respnum)
X int respnum;
{
X int num;
X
X clear_message ();
X
X if ((num = prompt_num (ch, txt_read_resp)) == -1) {
X clear_message ();
X return -1;
X }
X
X return choose_response (which_thread (respnum), num);
}
X
X
void yank_to_addr (orig, addr)
X char *orig;
X char *addr;
{
X char *p;
X
X for (p = orig; *p; p++)
X if (((*p) & 0xFF) < ' ')
X *p = ' ';
X
X while (*addr)
X addr++;
X
X while (*orig) {
X while (*orig && (*orig == ' ' || *orig == '"' || *orig == ','))
X orig++;
X *addr++ = ' ';
X while (*orig && (*orig != ' ' && *orig != ',' && *orig != '"'))
X *addr++ = *orig++;
X while (*orig && (*orig == ' ' || *orig == '"' || *orig == ','))
X orig++;
X if (*orig == '(') {
X while (*orig && *orig != ')')
X orig++;
X if (*orig == ')')
X orig++;
X }
X }
X *addr = '\0';
}
X
X
int show_last_page ()
{
X char buf[LEN];
X char buf2[LEN+50];
X char *p, *q;
X int ctrl_L; /* form feed character detected */
X int i, j;
X long tmp_pos;
X
X if (note_end) {
X return FALSE;
X }
X
X if (note_size == 0L) {
X tmp_pos = ftell (note_fp);
X fseek (note_fp, 0L, 2); /* goto end of article */
X note_size = ftell (note_fp);
X fseek (note_fp, tmp_pos, 0); /* goto old position */
X }
X
X while (! note_end) {
X note_line = 1;
X ctrl_L = FALSE;
X
X if (note_page == 0) {
X note_line += 4;
X } else {
X note_line += 2;
X }
X while (note_line < LINES) {
X if (fgets (buf, sizeof buf, note_fp) == NULL) {
X note_end = TRUE;
X break;
X }
X buf[LEN-1] = '\0';
X for (p = buf, q = buf2; *p && *p != '\n' && q<&buf2[LEN]; p++) {
X if (*p == '\b' && q > buf2) {
X q--;
X } else if (*p == 12) { /* ^L */
X *q++ = '^';
X *q++ = 'L';
X ctrl_L = TRUE;
X } else if (*p == '\t') {
X i = q - buf2;
X j = (i|7) + 1;
X
X while (i++ < j) {
X *q++ = ' ';
X }
X } else if (((*p) & 0xFF) < ' ') {
X *q++ = '^';
X *q++ = ((*p) & 0xFF) + '@';
X } else {
X *q++ = *p;
X }
X }
X *q = '\0';
X note_line += ((int) strlen (buf2) / COLS) + 1;
X
X if (ctrl_L) {
X break;
X }
X }
X if (note_mark[note_page] == note_size) {
X note_end = TRUE;
X note_page--;
X break;
X } else if (! note_end) {
X note_mark[++note_page] = ftell(note_fp);
X }
X }
X fseek (note_fp, note_mark[note_page], 0);
X return TRUE;
}
X
X
int match_header (buf, pat, body, len)
X char *buf;
X char *pat;
X char *body;
X int len;
{
X int plen = strlen (pat);
X
X if(strncmp (buf, pat, plen) == 0 && buf[plen] == ':' && buf[plen + 1] == ' ') {
X plen += 2;
X while (buf[plen] == ' ')
X plen++;
X strncpy (body, &buf[plen], len);
X body[len - 1] = '\0';
X return TRUE;
X }
X return FALSE;
}
SHAR_EOF
chmod 0600 page.c ||
echo 'restore of page.c failed'
Wc_c="`wc -c < 'page.c'`"
test 23335 -eq "$Wc_c" ||
echo 'page.c: original size 23335, current size' "$Wc_c"
rm -f _shar_wnt_.tmp
fi
# ============= post.c ==============
if test -f 'post.c' -a X"$1" != X"-c"; then
echo 'x - skipping post.c (File already exists)'
rm -f _shar_wnt_.tmp
else
> _shar_wnt_.tmp
echo 'x - extracting post.c (Text)'
sed 's/^X//' << 'SHAR_EOF' > 'post.c' &&
/*
X * Project : tin - a threaded Netnews reader
X * Module : post.c
X * Author : I.Lea
X * Created : 01-04-91
X * Updated : 22-01-92
X * Notes : mailing/posting/replying/followup & cancel article routines
X * Copyright : (c) Copyright 1991-92 by Rich Skrenta & 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 note_h_distrib[LEN]; /* Distribution: */
extern char note_h_followup[LEN]; /* Followup-To: */
extern char note_h_messageid[LEN]; /* Message-ID: */
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 cur_groupnum;
extern long note_mark[MAX_PAGES]; /* ftells on beginnings of pages */
X
char default_post_subject[LEN]; /* offers user default choice */
X
struct posted_t *posted;
X
X
int user_posted_messages ()
{
X char buf[LEN];
X FILE *fp;
X int i, j, k;
X int no_of_lines = 0;
X
X set_real_uid_gid ();
X
X if ((fp = fopen (postfile, "r")) == NULL) {
X clear_message ();
X set_tin_uid_gid ();
X return FALSE;
X } else {
X while (fgets (buf, sizeof (buf), fp) != NULL) {
X no_of_lines++;
X }
X if (! no_of_lines) {
X fclose (fp);
X info_message (txt_no_arts_posted);
X return FALSE;
X }
X rewind (fp);
X posted = (struct posted_t *) my_malloc ((unsigned) (no_of_lines+1) * sizeof (struct posted_t));
X for (i=0 ; fgets (buf, sizeof (buf), fp) != NULL ; i++) {
X for (j=0 ; buf[j] != '|' && buf[j] != '\n' ; j++) {
X posted[i].date[j] = buf[j]; /* posted date */
X }
X if (buf[j] == '\n') {
X error_message ("Corrupted file %s", postfile);
X sleep (1);
X fclose (fp);
X clear_message ();
X return FALSE;
X }
X posted[i].date[j++] = '\0';
X for (k=j,j=0 ; buf[k] != '|' && buf[k] != ',' ; k++, j++) {
X posted[i].group[j] = buf[k];
X }
X if (buf[k] == ',') {
X while (buf[k] != '|' && buf[k] != '\n') {
X k++;
X }
X posted[i].group[j++] = ',';
X posted[i].group[j++] = '.';
X posted[i].group[j++] = '.';
X posted[i].group[j++] = '.';
X }
X posted[i].group[j++] = '\0';
X k++;
X for (j=k,k=0 ; buf[j] != '\n' ; j++, k++) {
X posted[i].subj[k] = buf[j];
X }
X posted[i].subj[k++] = '\0';
X }
X fclose (fp);
X set_tin_uid_gid ();
X
X show_info_page (POST_INFO, (char **) 0, txt_post_history_menu);
X if (posted != (struct posted_t *) 0) {
X free ((char *) posted);
X posted = (struct posted_t *) 0;
X }
X return TRUE;
X }
}
X
X
void update_art_posted_file (group, subj)
X char *group;
X char *subj;
{
X char buf[LEN];
X char tmp_post[LEN];
X FILE *fp, *tmp_fp;
X long epoch;
X struct tm *tm;
X
X sprintf (tmp_post, "%s.%d", postfile, getpid ());
X
X set_real_uid_gid ();
X
X if ((tmp_fp = fopen (tmp_post, "w")) != NULL) {
X time (&epoch);
X tm = localtime (&epoch);
X fprintf (tmp_fp, "%02d-%02d-%02d|%s|%s\n",
X tm->tm_mday, tm->tm_mon+1, tm->tm_year, group, subj);
X fclose (tmp_fp);
X }
X
X if ((tmp_fp = fopen (tmp_post, "a+")) != NULL) {
X if ((fp = fopen (postfile, "r")) != NULL) {
X while (fgets (buf, sizeof buf, fp) != NULL) {
X fprintf (tmp_fp, "%s", buf);
X }
X fclose (fp);
X rename_file (tmp_post, postfile);
X }
X fclose (tmp_fp);
X }
X set_tin_uid_gid ();
}
X
/*
X * Post an original article (not a followup)
X */
X
int post_base (group, posted)
X char *group;
X int *posted;
{
X FILE *fp;
X char ch;
X char ch_default = 'p';
X char subj[LEN];
X char buf[LEN];
X int redraw_screen = FALSE;
X
X *posted = FALSE;
X start_line_offset = 4;
X
X if (active[my_group[cur_groupnum]].moderated == 'm') {
X sprintf (msg, "Group %s is moderated. Continue? (y/n): ", group);
X if (! prompt_yn (LINES, msg, 'y')) {
X clear_message ();
X return (redraw_screen);
X }
X }
X
X sprintf (msg, txt_post_subject, default_post_subject);
X
X if (! prompt_string (msg, subj)) {
X clear_message ();
X return (redraw_screen);
X }
X
X if (strlen (subj)) {
X my_strncpy (default_post_subject, subj, LEN);
X } else {
X if (default_post_subject[0]) {
X my_strncpy (subj, default_post_subject, LEN);
X } else {
X info_message (txt_no_subject);
X return (redraw_screen);
X }
X }
X
X wait_message (txt_post_an_article);
X
X set_real_uid_gid ();
X
X if ((fp = fopen (article, "w")) == NULL) {
X error_message (txt_cannot_open, article);
X set_tin_uid_gid ();
X return (redraw_screen);
X }
X chmod (article, 0600);
X
X fprintf (fp, "Subject: %s\n", subj);
X fprintf (fp, "Newsgroups: %s\n", group);
X fprintf (fp, "Distribution: \n");
X if (*my_org) {
X fprintf (fp, "Organization: %s\n", my_org);
X start_line_offset++;
X }
X if (*reply_to) {
X fprintf (fp, "Reply-To: %s\n", reply_to);
X start_line_offset++;
X }
X fprintf (fp, "\n");
X
X add_signature (fp, FALSE);
X fclose (fp);
X
X ch = 'e';
X while (1) {
X switch (ch) {
X case 'e':
X invoke_editor (article);
X set_real_uid_gid ();
X redraw_screen = TRUE;
X break;
X
X case 'a':
X case ESC:
X unlink (article);
X clear_message ();
X set_tin_uid_gid ();
X return (redraw_screen);
X
X case 'p':
X wait_message (txt_posting);
X if (submit_file (article)) {
X info_message (txt_art_posted);
X *posted = TRUE;
X goto post_base_done;
X } else {
X rename_file (article, dead_article);
X sprintf (buf, txt_art_rejected, dead_article);
X info_message (buf);
X sleep (3);
X set_tin_uid_gid ();
X return (redraw_screen);
X }
X }
X
X do {
X sprintf (msg, "%s%c", txt_abort_edit_post, ch_default);
X wait_message (msg);
X MoveCursor (LINES, (int) strlen (txt_abort_edit_post));
X if ((ch = (char) ReadCh ()) == CR)
X ch = ch_default;
X } while (ch != ESC && ch != 'a' && ch != 'e' && ch != 'p');
X }
X
post_base_done:
X find_mail_header (HEADER_SUBJECT, article, subj);
X unlink (article);
X set_tin_uid_gid ();
X update_art_posted_file (group, subj);
X return (redraw_screen);
}
X
X
int post_response (group, respnum, copy_text)
X char *group;
X int respnum;
X int copy_text;
{
X FILE *fp;
X char ch, *ptr;
X char ch_default = 'p';
X char buf[LEN];
X int ret_code = POSTED_NONE;
X
X start_line_offset = 4;
X
X wait_message (txt_post_a_followup);
X
X if (*note_h_followup && strcmp (note_h_followup, "poster") == 0) {
X clear_message ();
X if (! prompt_yn (LINES, txt_resp_to_poster, 'y')) {
X return (ret_code);
X }
X *note_h_followup = '\0';
X } else if (*note_h_followup && strcmp(note_h_followup, group) != 0) {
X MoveCursor (LINES/2, 0);
X CleartoEOS ();
X center_line ((LINES/2)+2, TRUE, txt_resp_redirect);
X MoveCursor ((LINES/2)+4, 0);
X
X printf (" ");
X ptr = note_h_followup;
X while (*ptr) {
X if (*ptr != ',') {
X putc (*ptr, stdout);
X } else {
X printf ("\r\n ");
X }
X fflush (stdout);
X ptr++;
X }
X
X if (! prompt_yn (LINES, txt_continue, 'y')) {
X return (ret_code);
X }
X }
X
X set_real_uid_gid ();
X
X if ((fp = fopen (article, "w")) == NULL) {
X error_message (txt_cannot_open, article);
X set_tin_uid_gid ();
X return (ret_code);
X }
X chmod (article, 0600);
X
X fprintf (fp, "Subject: Re: %s\n", eat_re (note_h_subj));
X
X if (*note_h_followup && strcmp(note_h_followup, "poster") != 0) {
X fprintf (fp, "Newsgroups: %s\n", note_h_followup);
X } else {
X fprintf (fp, "Newsgroups: %s\n", note_h_newsgroups);
X }
X if (note_h_distrib != '\0') {
X fprintf (fp, "Distribution: %s\n", note_h_distrib);
X start_line_offset++;
X }
X fprintf (fp, "References: %s\n", note_h_messageid);
X
X if (*my_org) {
X fprintf (fp, "Organization: %s\n", my_org);
X start_line_offset++;
X }
X if (*reply_to) {
X fprintf (fp, "Reply-To: %s\n", reply_to);
X start_line_offset++;
X }
X fprintf (fp, "\n");
X
X if (copy_text) { /* if "copy_text" */
X if (arts[respnum].from != (char *) 0) {
X if (arts[respnum].name == arts[respnum].from) {
X fprintf (fp, txt_writes, arts[respnum].from);
X } else {
X fprintf (fp, txt_writes_name, arts[respnum].from, arts[respnum].name);
X }
X }
X fseek (note_fp, note_mark[0], 0);
X copy_fp (note_fp, fp, DEFAULT_COMMENT);
X }
X
X add_signature (fp, FALSE);
X fclose (fp);
X
X ch = 'e';
X while (1) {
X switch (ch) {
X case 'e':
X invoke_editor (article);
X set_real_uid_gid ();
X ret_code = POSTED_REDRAW;
X break;
X
X case 'a':
X case ESC:
X unlink (article);
X clear_message ();
X set_tin_uid_gid ();
X return (ret_code);
X
X case 'p':
X wait_message (txt_posting);
X if (submit_file (article)) {
X ret_code = POSTED_OK;
X info_message (txt_art_posted);
X goto post_response_done;
X } else {
X rename_file (article, dead_article);
X sprintf (buf, txt_art_rejected, dead_article);
X info_message (buf);
X sleep (3);
X set_tin_uid_gid ();
X return (ret_code);
X }
X }
X
X do {
X sprintf (msg, "%s%c", txt_abort_edit_post, ch_default);
X wait_message (msg);
X MoveCursor(LINES, (int) strlen (txt_abort_edit_post));
X if ((ch = (char) ReadCh()) == CR)
X ch = ch_default;
X } while (ch != ESC && ch != 'a' && ch != 'e' && ch != 'p');
X }
X
post_response_done:
X if (*note_h_followup && strcmp(note_h_followup, "poster") != 0) {
X find_mail_header (HEADER_SUBJECT, article, note_h_subj);
X update_art_posted_file (note_h_followup, note_h_subj);
X } else {
X find_mail_header (HEADER_SUBJECT, article, note_h_subj);
X update_art_posted_file (note_h_newsgroups, note_h_subj);
X }
X
X set_real_uid_gid ();
X unlink (article);
X set_tin_uid_gid ();
X
X return (ret_code);
}
X
X
int mail_to_someone (address)
X char *address;
{
X char nam[100];
X char ch, ch_default = 's';
X char buf[LEN];
X char mail_to[LEN];
X FILE *fp;
X int redraw_screen = FALSE;
SHAR_EOF
true || echo 'restore of post.c failed'
fi
echo 'End of tin1.1 part 7'
echo 'File post.c is continued in part 8'
echo 8 > _shar_seq_.tmp
exit 0
--
NAME Iain Lea
EMAIL iain%estevax.uucp@unido.Informatik.Uni-Dortmund.DE
SNAIL Bruecken Strasse 12, 8500 Nuernberg 90, Germany
PHONE +49-911-331963 (home) +49-911-3089-407 (work)
--
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...