v19i063: NN, a Usenet news reader, Part02/15
Rich Salz
rsalz at uunet.uu.net
Sat Jun 24 02:24:03 AEST 1989
Submitted-by: storm at texas.dk (Kim F. Storm)
Posting-number: Volume 19, Issue 63
Archive-name: nn/part02
#!/bin/sh
# this is part 2 of a multipart archive
# do not concatenate these parts, unpack them in order with /bin/sh
# file admin.c continued
#
CurArch=2
if test ! -r s2_seq_.tmp
then echo "Please unpack part 1 first!"
exit 1; fi
( read Scheck
if test "$Scheck" != $CurArch
then echo "Please unpack part $Scheck next!"
exit 1;
else exit 0; fi
) < s2_seq_.tmp || exit 1
echo "x - Continuing file admin.c"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> admin.c
X printf("You must restart nnadmin to access the new group(s)\n");
X ngp = master.number_of_groups;
X }
X
X ngp = 0;
X
X Loop_Groups_Header(gh)
X if (update_group(gh) < 0) ngp++;
X
X if (ngp) printf("There are %d blocked groups\n", ngp);
X}
X
X
Xstatic master_admin()
X{
X register char c;
X int cur_group, value;
X register group_header *gh;
X
X for (;;) {
X switch (c = get_cmd(
X"\nG)roup A)ll E)mpty N)on-empty F)iles O)ptions S)tat T)race K)ill",
X"MASTER")) {
X
X case 'G':
X cur_group = get_entry("Group number",
X 0L, (long)(master.number_of_groups - 1));
X if (cur_group >= 0)
X dump_m_entry(&active_groups[cur_group]);
X break;
X
X case 'A':
X case 'E':
X case 'N':
X cur_group = -1;
X s_keyboard = 0;
X
X while (++cur_group < master.number_of_groups) {
X if (s_keyboard || s_hangup) break;
X
X gh = &active_groups[cur_group];
X if (c == 'N' && gh->last_l_article == 0) continue;
X if (c == 'E' && gh->last_l_article != 0) continue;
X dump_m_entry(gh);
X }
X break;
X
X case 'F':
X find_files(-1);
X break;
X
X case 'O':
X c = get_cmd("r)epeat_delay e)xpire_level", "OPTION");
X if (c != 'r' && c != 'e') break;
X value = get_entry("Option value", 1, 10000);
X if (value < 0) break;
X send_master(c, (long)value, 0L);
X break;
X
X case 'S':
X master_status();
X break;
X
X case 'T':
X send_master('T', 0L, 0L);
X break;
X
X case 'K':
X if (admin_confirm("Stop nn Master"))
X kill_master_1(SIGHUP);
X break;
X
X default:
X return;
X }
X }
X}
X
X
Xstatic log_admin()
X{
X char command[FILENAME + 100], c;
X
X if (pre_input && *pre_input == NUL) {
X c = SP;
X goto log_tail;
X }
X
X loop:
X
X c = get_cmd(
X"\nE)rrors R)eports C)ollect e(X)pire A)dmin G)roup (1-9)tail (*)all (@)clean",
X"LOG");
X
X if (c < SP || c == 'Q') return;
X
X if (c == '@') {
X if (admin_confirm("Truncation")) {
X sprintf(command,
X"cd %s && mv Log Log.old && ./log_entry A Truncated && chmod 666 Log",
X lib_directory);
X system(command);
X }
X return;
X }
X
X if (c == 'G') {
X char *groupname;
X
X raw();
X printf("Group: ");
X fl;
X groupname = get_s(NONE, NONE, NONE, group_completion);
X no_raw();
X
X putchar(NL); putchar(CR);
X
X if (groupname == NULL) return;
X
X sprintf(command, "grep '%s' %s/Log | %s",
X groupname, lib_directory, pager);
X system(command);
X
X goto loop;
X }
X
X log_tail:
X if (c == '$' || c == SP || isdigit(c)) {
X int n;
X
X n = isdigit(c) ? 10 * (c - '0') : 10;
X sprintf(command, "tail -%d %s/Log", n, lib_directory);
X system(command);
X goto loop;
X }
X
X if (c == '*') {
X c = '.';
X }
X
X sprintf(command, "grep '^%c:' %s/Log | %s", c, lib_directory, pager);
X system(command);
X
X goto loop;
X}
X
X
Xstatic group_admin()
X{
X char *groupname;
X register group_header *gh;
X
X new_group:
X
X raw();
X printf("Group: ");
X fl;
X groupname = get_s(NONE, NONE, NONE, group_completion);
X no_raw();
X
X putchar(NL); putchar(CR);
X
X if (groupname == NULL) return;
X
X gh = lookup(groupname);
X if (gh == NULL) {
X printf("No group named %s\n", groupname);
X goto new_group;
X }
X
X for (;;) {
X switch (get_cmd(
X"\nD)ata H)eader F)iles S)et_flag C)lear_flag E)xpire R)ecollect G)roup",
X"GROUP")) {
X case 'D':
X dump_group(gh, 0);
X break;
X
X case 'H':
X dump_m_entry(gh);
X break;
X
X case 'F':
X find_files(gh->group_num);
X break;
X
X case 'S':
X flag_admin(gh, "Set", 1);
X break;
X
X case 'C':
X flag_admin(gh, "Clear", 0);
X break;
X
X case 'R':
X if (admin_confirm("Recolletion of Group"))
X send_master('R', (long)gh->group_num, 0L);
X break;
X
X case 'E':
X if (admin_confirm("Expire Group"))
X send_master('X', (long)gh->group_num, 0L);
X break;
X
X case 'G':
X goto new_group;
X
X default:
X return;
X }
X }
X}
X
X
Xstatic flag_admin(gh, mode_str, set_flag)
Xgroup_header *gh;
Xchar *mode_str;
Xint set_flag;
X{
X char buffer[50];
X int new_flag = 0;
X
X putchar(NL);
X
X dump_g_flag(gh);
X
X sprintf(buffer, "%s FLAG", mode_str);
X
X switch (get_cmd(
X"\nA)lways_digest N)ever_digest M)oderated C)ontrol no_(D)ir",
Xbuffer)) {
X
X default:
X return;
X
X case 'M':
X new_flag = G_MODERATED;
X break;
X
X case 'C':
X new_flag = G_CONTROL;
X break;
X
X case 'D':
X new_flag = G_NO_DIRECTORY;
X break;
X
X case 'A':
X new_flag = G_ALWAYS_DIGEST;
X break;
X
X case 'N':
X new_flag = G_NEVER_DIGEST;
X break;
X }
X
X if (new_flag & (G_CONTROL | G_NO_DIRECTORY))
X if (!admin_confirm("Flag Change"))
X new_flag = 0;
X
X if (new_flag) {
X if (set_flag) {
X if (gh->group_flag & new_flag)
X new_flag = 0;
X else {
X send_master('S', (long)gh->group_num, (long)new_flag);
X gh->group_flag |= new_flag;
X }
X } else {
X if ((gh->group_flag & new_flag) == 0)
X new_flag = 0;
X else {
X send_master('C', (long)gh->group_num, (long)new_flag);
X gh->group_flag &= ~new_flag;
X }
X }
X }
X
X if (new_flag == 0)
X printf("NO CHANGE\n");
X else
X dump_g_flag(gh);
X}
X
X
Xstatic find_files(group)
Xgroup_number group;
X{
X char command[512];
X
X if (group < 0)
X sprintf(command, "ls -l %s/DATA | %s", db_directory, pager);
X else
X sprintf(command, "ls -l %s/DATA/%d.*", db_directory, group);
X system(command);
X}
X
X
Xstatic master_status()
X{
X int cur_group;
X long articles, disk_use;
X register group_header *gh;
X
X printf("\nMaster:\n");
X printf(" last_scan: %s\n", date_time(master.last_scan));
X printf(" no of groups: %d\n", master.number_of_groups);
X printf(" next write: %ld\n", master.next_group_write_offset);
X
X articles = disk_use = 0;
X
X for (cur_group = 0; cur_group < master.number_of_groups; cur_group++) {
X gh = &active_groups[cur_group];
X
X#define DISK_BLOCKS(bytes) (((bytes) + 1023) / 1024)
X
X disk_use += DISK_BLOCKS(gh->index_write_offset);
X disk_use += DISK_BLOCKS(gh->data_write_offset);
X
X articles += gh->last_l_article - gh->first_l_article + 1;
X }
X
X printf("\n Articles: %ld\n", articles);
X printf( " Disk usage: %ld k\n", disk_use);
X}
X
Xstatic show_config()
X{
X extern char *temp_file;
X extern char news_active[], news_directory[];
X#ifdef NNTP
X extern char nntp_server[];
X#endif
X
X printf("\nConfiguration:\n\n");
X printf("BIN: %s\nLIB: %s\nDB: %s\nNEWS: %s\n",
X BIN_DIRECTORY,
X lib_directory,
X db_directory,
X news_directory);
X
X printf("ACTIVE: %s\n", news_active);
X
X#ifdef NNTP
X if (use_nntp)
X printf("NNTP ACTIVE. server=%s\n", nntp_server);
X else
X printf("NNTP NOT ACTIVE\n");
X#endif
X
X#ifdef NETWORK_DATABASE
X printf("Database is machine independent (network format).\n");
X#ifdef NETWORK_BYTE_ORDER
X printf("Local system assumes to use network byte order\n");
X#endif
X#else
X printf("Database format is machine dependent (byte order and alignment)\n");
X#endif
X
X#ifdef STATISTICS
X printf("Recording usage statistics\n");
X#else
X printf("No usage statistics are recorded\n");
X#endif
X
X printf("Default pager: %s\n", PAGER);
X printf("Default printer: %s\n", PRINTER);
X
X printf("Mail delivery program: %s\n", REC_MAIL);
X#ifdef APPEND_SIGNATURE
X printf("Query for appending .signature ENABLED\n");
X#else
X printf("Query for appending .signature DISABLED\n");
X#endif
X
X printf("Max pathname length is %d bytes\n", FILENAME-1);
X}
X
Xstatic dump_m_entry(gh)
Xregister group_header *gh;
X{
X update_group(gh);
X
X printf("\n%s\t%d\n", gh->group_name, gh->group_num);
X printf("first/last art: %06ld %06d\n",
X gh->first_l_article, gh->last_l_article);
X printf(" active info: %06ld %06d\n",
X gh->first_article, gh->last_article);
X printf("Offsets: index->%ld, data->%ld\n",
X gh->index_write_offset,
X gh->data_write_offset);
X if (gh->group_flag)
X dump_g_flag(gh);
X}
X
Xstatic dump_g_flag(gh)
Xregister group_header *gh;
X{
X printf("Flags: ");
X if (gh->group_flag & G_BLOCKED) printf(" BLOCKED");
X if (gh->group_flag & G_EXPIRE) printf(" EXPIRE");
X if (gh->group_flag & G_MODERATED) printf(" MODERATED");
X if (gh->group_flag & G_CONTROL) printf(" CONTROL");
X if (gh->group_flag & G_NO_DIRECTORY) printf(" NO_DIRECTORY");
X if (gh->group_flag & G_ALWAYS_DIGEST) printf(" ALWAYS_DIGEST");
X if (gh->group_flag & G_NEVER_DIGEST) printf(" NEVER_DIGEST");
X printf("\n");
X}
X
X
Xstatic dump_group(gh, validate)
Xgroup_header *gh;
Xint validate;
X{
X FILE *data, *ix;
X data_header hdr;
X off_t data_offset, real_offset, next_offset;
X cross_post_number cross_post;
X article_number first_article, next_article, this_art;
X int n, was_digest;
X char buffer[512];
X
X if (init_group(gh) <= 0)
X printf("cannot access group %s\n", gh->group_name);
X
X update_group(gh);
X
X if (validate)
X first_article = gh->first_l_article;
X else
X first_article = get_entry("First article",
X (long)gh->first_l_article,
X (long)gh->last_l_article);
X
X if (first_article < 0) first_article = gh->first_l_article;
X
X ix = open_data_file(gh, 'x', OPEN_READ);
X if (ix == NULL) {
X if (verbose) printf("NO INDEX FILE\n");
X return 0;
X }
X next_offset = get_index_offset(gh, first_article);
X fseek(ix, next_offset, 0);
X
X if (!db_read_offset(ix, &real_offset)) {
X if (verbose) printf("NO INDEX FOR ARTICLE %ld\n", (long)first_article);
X fclose(ix);
X return 0;
X }
X
X data_offset = real_offset;
X fseek(ix, next_offset, 0);
X
X data = open_data_file(gh, 'd', OPEN_READ);
X if (data == NULL) {
X if (verbose) printf("NO DATA FILE\n");
X fclose(ix);
X return 0;
X }
X
X
X next_article = first_article;
X s_keyboard = 0;
X was_digest = 0;
X
X while (next_article <= gh->last_l_article) {
X if (s_hangup || s_keyboard) goto out;
X
X if (!db_read_offset(ix, &real_offset)) {
X if (verbose)
X printf("NO INDEX FOR ARTICLE %ld\n", (long)next_article);
X goto err;
X }
X
X if (data_offset != real_offset)
X goto ix_data_err;
X
X fseek(data, data_offset, 0);
X
X in_digest:
X
X next_offset = data_offset;
X if (!db_read_art(data, &hdr, &data_offset)) {
X if (real_offset == gh->data_write_offset || was_digest)
X break;
X
X if (verbose) printf("No article header for article # %ld\n",
X (long)next_article);
X goto err;
X }
X
X if (hdr.dh_number) {
X if (was_digest) {
X next_article++;
X if (!db_read_offset(ix, &real_offset))
X goto ix_eof_err;
X if (real_offset != next_offset)
X goto ix_data_err;
X }
X
X this_art = hdr.dh_number < 0 ? -hdr.dh_number : hdr.dh_number;
X
X if (this_art != next_article) {
X if (this_art < next_article) {
X if (verbose)
X printf("Article # %ld out of sequence\n",
X (long)this_art);
X goto err;
X }
X/*
X if (this_art == (next_article + 1))
X printf("Article # %ld missing (OK)\n",
X (long)next_article);
X else
X printf("Articles # %ld -> %ld missing (OK)\n",
X (long)next_article, (long)this_art);
X*/
X while (this_art > next_article) {
X if (!db_read_offset(ix, &next_offset))
X goto ix_eof_err;
X if (next_offset != real_offset)
X goto ix_data_err;
X next_article++;
X }
X }
X }
X
X if (!validate)
X printf("\noffset = %ld, article # = %ld\n",
X (long)real_offset, (long)(hdr.dh_number));
X
X if (hdr.dh_lpos == (off_t)0) { /* article not accessible */
X if (verbose)
X printf("# %ld: NO ARTICLE (ok)\n", (long)next_article);
X continue;
X }
X
X data_offset += hdr.dh_cross_postings * sizeof(cross_post_number)
X + hdr.dh_sender_length
X + hdr.dh_subject_length;
X
X if (hdr.dh_cross_postings) {
X if (!validate)
X printf("xpost(%d):", hdr.dh_cross_postings);
X
X n = hdr.dh_cross_postings;
X while (--n >= 0) {
X if (fread((char *)&cross_post, sizeof(cross_post_number), 1, data)!= 1)
X goto data_error;
X#ifdef NETWORK_DATABASE
X#ifndef NETWORK_BYTE_ORDER
X cross_post = ntohl(cross_post);
X#endif
X#endif
X if (validate) {
X if (cross_post >= master.number_of_groups) {
X if (verbose)
X printf("xpost group out of range: %ld (article # %ld)\n",
X (long)cross_post, (long)next_article);
X goto err;
X }
X } else
X printf(" %d", cross_post);
X }
X if (!validate) printf("\n");
X }
X
X
X if (!validate)
X if (IS_DIGEST_HEADER(hdr))
X printf("digest header ");
X else
X if (IS_SUB_DIGEST(hdr))
X printf("digest article ");
X else
X printf("normal article ");
X
X if (!validate)
X printf("ts=%lu hp=%ld, fp=+%d, lp=%ld, rep=%d, lines=%d\n",
X (long unsigned)hdr.dh_date,
X (long)hdr.dh_hpos, (int)hdr.dh_fpos, (long)hdr.dh_lpos,
X hdr.dh_replies, hdr.dh_lines);
X
X if (hdr.dh_sender_length) {
X if (fread(buffer, sizeof(char), (int)hdr.dh_sender_length, data)
X != hdr.dh_sender_length) goto data_error;
X buffer[hdr.dh_sender_length] = NUL;
X if (!validate)
X printf("Sender(%d): %s\n", hdr.dh_sender_length, buffer);
X } else
X if (!validate)
X printf("No sender\n");
X
X if (hdr.dh_subject_length) {
X if (fread(buffer, sizeof(char), (int)hdr.dh_subject_length, data)
X != hdr.dh_subject_length) goto data_error;
X buffer[hdr.dh_subject_length] = NUL;
X if (!validate)
X printf("Subj(%d): %s\n", hdr.dh_subject_length, buffer);
X } else
X if (!validate)
X printf("No subject\n");
X
X if (IS_DIGEST_HEADER(hdr) || IS_SUB_DIGEST(hdr)) {
X was_digest = 1;
X goto in_digest;
X }
X
X was_digest = 0;
X next_article++;
X
X }
X
Xout:
X
X if (s_keyboard == 0 && data_offset != gh->data_write_offset) {
X if (verbose)
X printf("\n*** ERROR: Next data offset %ld wrong. real offset=%ld\n",
X gh->data_write_offset, data_offset);
X goto err;
X }
X
X fclose(data);
X fclose(ix);
X return 1;
X
X
X
X data_error:
X if (verbose) printf("\n*** END OF FILE on DATA FILE\n\n");
X goto err;
X
X ix_eof_err:
X if (verbose) printf("NO INDEX FOR ARTICLE %ld\n", (long)next_article);
X goto err;
X
X ix_data_err:
X if (verbose) {
X printf("\n*** OFFSET ERROR in article # %ld offsets:\n",
X (long)next_article);
X printf(" Calcuated offset %ld differs from index %ld\n",
X (long)data_offset, (long)real_offset);
X }
X goto err;
X
X err:
X
X fclose(data);
X fclose(ix);
X return 0;
X}
X
X
Xsend_master(command, arg1, arg2)
Xchar command;
Xlong arg1, arg2;
X{
X FILE *gate;
X
X gate = open_file(relative(lib_directory, "GATE"), OPEN_APPEND);
X
X if (gate == NULL) {
X printf("Cannot send to master\n");
X return;
X }
X
X fprintf(gate, "%c;%ld;%ld;%s %s;\n",
X command, arg1, arg2, user_name(), date_time((time_t)0));
X
X fclose(gate);
X
X log_entry('A', "SEND %c %ld %ld", command, arg1, arg2);
X}
X
X
X
X
X/* fake this for visit_active_file() */
X
X/*ARGSUSED*/
Xgroup_header *add_new_group(name)
Xchar *name;
X{
X return NULL;
X}
X
X
X/*
X * make consistency check on all groups
X */
X
X
Xstatic file_error(gh, d_or_x, write_offset)
Xgroup_header *gh;
Xchar d_or_x;
Xoff_t write_offset;
X{
X FILE *f;
X
X f = open_data_file(gh, d_or_x, OPEN_READ);
X
X if (f == NULL) {
X if (verbose)
X printf("FILE '%c' NOT FOUND\n", d_or_x);
X } else {
X fseek(f, (off_t)0, 2);
X if (ftell(f) >= write_offset) {
X fclose(f);
X return 0;
X }
X
X if (verbose)
X printf("FILE '%c' IS SHORTER THAN NEXT WRITE OFFSET\n", d_or_x);
X fclose(f);
X }
X
X return 1;
X}
X
X
Xvalidate_groups()
X{
X register group_header *gh;
X group_number num;
X import char *pname;
X
X if (strcmp(pname, "nnadmin")) {
X printf("You can only run VALIDATION from nnadmin\n");
X return;
X }
X
X s_keyboard = 0;
X
X Loop_Groups_Number(num) {
X
X if (s_hangup || s_keyboard) break;
X
X gh = &active_groups[num];
X if (init_group(gh) <= 0) continue; /* no directory */
X
X if (verbose) { printf("\r%s: ", gh->group_name); clrline(); }
X
X if (gh->group_flag & G_BLOCKED) {
X if (verbose) printf("BLOCKED\n");
X continue;
X }
X
X /*
X * Check for major inconcistencies.
X * Sometimes, news expire will reset article numbers
X * to start from 0 again
X */
X
X if (gh->last_l_article == 0) {
X continue;
X }
X
X if (gh->first_article > gh->last_l_article ||
X gh->last_l_article > gh->last_article ||
X gh->first_l_article > gh->first_article) {
X
X if (verbose)
X printf("RENUMBERING OF ARTICLES (active=%ld..%ld master=%ld..%ld)",
X gh->first_article, gh->last_article,
X gh->first_l_article, gh->last_l_article);
X goto ask_collect;
X }
X
X /*
X * Check existence and sizes of data files
X */
X
X if (file_error(gh, 'x', gh->index_write_offset))
X goto ask_collect;
X
X if (file_error(gh, 'd', gh->data_write_offset))
X goto ask_collect;
X
X if (!dump_group(gh, 1))
X goto ask_collect;
X
X if (!verbose) continue;
X
X if (gh->first_article > gh->first_l_article)
X printf("unexpired articles: %ld\n",
X (long)(gh->first_article - gh->first_l_article));
X else
X printf("OK\r");
X continue;
X
X ask_collect:
X log_entry('V', "Database inconsistency in group %s", gh->group_name);
X
X if (admin_confirm("\nRepair group"))
X send_master('R', (long)gh->group_num, 0L);
X }
X}
X
X
X
Xkill_master_1(sig)
Xint sig;
X{
X if (kill_master(sig)) {
X if (verbose) printf("sent signal %d to master\n", sig);
X } else
X if (errno == ESRCH) {
X if (verbose) printf("master is not running\n");
X } else
X printf("cannot signal master (errno=%d)\n", errno);
X}
NO_NEWS_IS_GOOD_NEWS
echo "File admin.c is complete"
chmod 0644 admin.c || echo "restore of admin.c fails"
set `wc -c admin.c`;Sum=$1
if test "$Sum" != "20076"
then echo original size 20076, current size $Sum;fi
echo "x - extracting answer.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > answer.c &&
X#include "config.h"
X#include "news.h"
X#include "term.h"
X#include "keymap.h"
X
Xextern char *temp_file;
X
Xchar *news_record = NULL;
Xchar *mail_record = NULL;
X
X
X#define INCL_MARK_SIZE 10
X
Xexport char included_mark[INCL_MARK_SIZE + 1] = ">";
X
X
Xstatic int ed_line;
X
X
Xanswer(ah, command, incl)
Xarticle_header *ah;
Xint command;
Xint incl; /* <0: ask, 0: don't include, >0: include article */
X{
X register FILE *t, *art;
X char *pgm, *first_action, *record_file;
X int edit_message;
X char *str;
X news_header_buffer nhbuf, dhbuf;
X
X first_action = "edit";
X edit_message = 1;
X
X if (incl < 0) {
X prompt("Include original article? ");
X if ((incl = yes(0)) < 0) return 0;
X }
X
X art = NULL;
X if (ah && ah->a_group) init_group(ah->a_group);
X
X if (incl || command != K_MAIL_OR_FORWARD) {
X int open_modes;
X
X open_modes = FILL_NEWS_HEADER | GET_ALL_FIELDS | SKIP_HEADER;
X if (ah->flag & A_DIGEST) open_modes |= FILL_DIGEST_HEADER;
X
X art = open_news_article(ah, open_modes, nhbuf, dhbuf);
X if (art == NULL) {
X msg("Can't find original article");
X return 0;
X }
X
X if (ah->flag & A_DIGEST) {
X if (digest.dg_from)
X news.ng_path = news.ng_from = digest.dg_from;
X if (digest.dg_subj)
X news.ng_subj = digest.dg_subj;
X }
X } else
X ah = NULL;
X
X /* build header */
X
X if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) {
X msg("Can't create %s", temp_file);
X return 0;
X }
X
X ed_line = 0;
X record_file = mail_record;
X
X if (command == K_REPLY) {
X pgm = "reply";
X
X if (reply_to(t, news.ng_reply) ||
X reply_to(t, news.ng_from) ||
X reply_to(t, news.ng_path)) goto alt0;
X if (to_line(t, news.ng_reply)) goto alt1;
X if (to_line(t, news.ng_from)) goto alt2;
X if (to_line(t, news.ng_path)) goto alt3;
X goto err;
X
X alt0:
X alt_to_line(t, news.ng_reply);
X alt1:
X alt_to_line(t, news.ng_from);
X alt2:
X alt_to_line(t, news.ng_path);
X alt3:
X
X if (news.ng_subj)
X subj_line(t, ah->replies, ah->subject, (char *)NULL);
X else
X subj_line(t, 0, current_group->group_name, "Your Article in");
X
X ng_line(t);
X ref_line(t);
X
X end_header(t);
X
X if (incl) {
X fprintf(t, "In %s you write:\n", current_group->group_name);
X ed_line++;
X }
X }
X
X if (command == K_FOLLOW_UP) {
X pgm = "follow";
X record_file = news_record;
X
X ng_line(t);
X
X if (news.ng_subj)
X subj_line(t, ah->replies, ah->subject, (char *)NULL);
X else
X if (!subj_line(t, 0, news.ng_from, "Babble from"))
X if (!subj_line(t, 0, news.ng_ident, "Article")) {
X prompt("Subject: ");
X str = get_s(NONE, NONE, NONE, NO_COMPLETION);
X if (str == NULL) goto err;
X subj_line(t, -1, str, (char *)NULL);
X }
X
X if (news.ng_keyw) {
X fprintf(t, "Keywords: %s\n", news.ng_keyw);
X ed_line++;
X }
X
X if (news.ng_dist) {
X fprintf(t, "Distribution: %s\n", news.ng_dist);
X ed_line++;
X }
X
X ref_line(t);
X
X end_header(t);
X
X if (incl) {
X if (news.ng_from) {
X fprintf(t, "%s writes:\n", news.ng_from);
X ed_line++;
X } else
X if (news.ng_ident) {
X fprintf(t, "In %s %s:\n",
X ah->flag & A_DIGEST ? "digest" : "article",
X news.ng_ident);
X ed_line++;
X }
X }
X }
X
X if (command == K_MAIL_OR_FORWARD) {
X pgm = incl ? "forward" : "mail";
X
X m3_again:
X prompt("To: ");
X str = get_s(user_name(), NONE, NONE, NO_COMPLETION);
X if (str == NULL) goto close_t;
X
X if (*str == NUL) str = user_name();
X if (*str == '?') goto m3_again;
X
X if (strcmp(str, user_name()) == 0)
X record_file = NULL; /* we will get this anyway,
X there is so no need to save it */
X
X/* if (reply_to(t, str)) { alt_to_line(t, str); } else */
X to_line(t, str);
X
X do {
X prompt("Subject: ");
X str = get_s(incl ? ah->subject : NONE, NONE, NONE, NO_COMPLETION);
X if (str == NULL) goto close_t;
X if (*str == NUL && incl) str = ah->subject;
X } while (*str == NUL);
X
X subj_line(t, -1, str, (char *)NULL);
X
X end_header(t);
X
X if (incl) {
X prompt("\1Edit\1 forwarded message? ");
X if ((edit_message = yes(0)) < 0) goto close_t;
X if (!edit_message) {
X first_action = "send";
X fseek(art, ah->hpos, 0);
X }
X }
X
X }
X
X /* empty line terminates header */
X fputc(NL, t);
X ed_line++;
X
X prompt("\1WAIT\1");
X
X if (incl) {
X register c, prevnl = 1;
X
X while ((c = getc(art)) != EOF) {
X if (c == NL) {
X putc(c, t);
X if (ftell(art) >= ah->lpos) break;
X prevnl++;
X continue;
X }
X if (prevnl) {
X if (command != K_MAIL_OR_FORWARD || ftell(art) < ah->fpos)
X fputs(included_mark, t);
X prevnl = 0;
X }
X putc(c, t);
X }
X } else {
X putc(NL, t);
X ed_line++;
X }
X
X fclose(t);
X if (art) fclose(art);
X
X aux_sh(pgm, first_action, record_file,
X command == K_FOLLOW_UP ? "Article not posted" : "Mail not sent");
X
X return edit_message;
X
X err:
X msg("Can't build header for %s",
X command != K_FOLLOW_UP ? "letter" : "article");
X
X close_t:
X fclose(t);
X unlink(temp_file);
X if (art) fclose(art);
X
X return 0;
X}
X
X
Xcancel(ah)
Xarticle_header *ah;
X{
X news_header_buffer nhbuf;
X FILE *f;
X
X if (ah->a_group) init_group(ah->a_group);
X
X if (ah->flag & A_DIGEST) {
X fputs("\rCancel entire digest ? ", stdout); clrline();
X if (yes(1) > 0)
X ah->flag &= ~A_DIGEST;
X else {
X msg("Can only cancel entire digests (yet?)");
X return 2;
X }
X } else {
X fputs("\rConfirm cancel: ", stdout); clrline();
X if (yes(1) <= 0) return 0;
X }
X
X f = open_news_article(ah, FILL_NEWS_HEADER|GET_ALL_FIELDS, nhbuf, (char *)NULL);
X if (f == NULL) {
X msg("Can't find original article");
X return 2;
X }
X fclose(f);
X
X printf("\rCancelling article %s in group %s",
X news.ng_ident, current_group->group_name);
X clrline();
X
X ed_line = -1;
X
X if (aux_sh("cancel",
X news.ng_ident, current_group->group_name, "Not canceled"))
X return 3;
X
X return 1;
X}
X
X
Xpost_menu()
X{
X FILE *t;
X char *str, *tail;
X char group_name[FILENAME], subject[FILENAME],
X distribution[FILENAME], keywords[FILENAME];
X extern group_completion();
X
X group_name[0] = NUL;
X
X again_group:
X
X prompt("\1POST to group\1 ");
X
X str = get_s(current_group ? current_group->group_name : NONE,
X group_name, NONE, group_completion);
X if (str == NULL || *str == NUL) return 0;
X strcpy(group_name, str);
X
X for (str = group_name; str; str = tail) {
X tail = strchr(str, ',');
X if (tail) *tail = NUL;
X
X if (lookup(str) == NULL) {
X msg("unknown group: %s", str);
X *str = NUL;
X goto again_group;
X }
X
X if (tail) *tail++ = ',';
X }
X
X prompt("Subject: ");
X str = get_s(NONE, NONE, NONE, NO_COMPLETION);
X if (str == NULL || *str == NUL) return 0;
X strcpy(subject, str);
X
X prompt("Keywords: ");
X str = get_s(NONE, NONE, NONE, NO_COMPLETION);
X if (str == NULL) return 0;
X strcpy(keywords, str);
X
X strcpy(distribution, group_name);
X if (str = strchr(distribution, '.')) *str = NUL;
X
X prompt("\1Distribution\1 (default '%s') ", distribution);
X str = get_s(NONE, NONE, NONE, NO_COMPLETION);
X if (str == NULL) return 0;
X if (*str) strcpy(distribution, str);
X
X if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) {
X msg("Can't create %s", temp_file);
X return 0;
X }
X
X prompt("\1WAIT\1");
X
X ed_line = 5;
X fprintf(t, "Newsgroups: %s\n", group_name);
X fprintf(t, "Distribution: %s\n", distribution);
X fprintf(t, "Subject: %s\n", subject);
X if (*keywords) {
X fprintf(t, "Keywords: %s\n", keywords);
X ed_line++;
X }
X fputc(NL, t);
X fputc(NL, t);
X
X fclose(t);
X
X aux_sh("post", "edit", news_record, "Article not posted");
X
X return 1;
X}
X
Xstatic subj_line(t, re, subj, prefix)
XFILE *t;
Xint re;
Xchar *subj, *prefix;
X{
X if (subj == NULL) return 0;
X
X fputs("Subject: ", t);
X
X if (re == 0)
X fputs("Re: ", t);
X else if (re > 0)
X fprintf(t, "Re^%d: ", re + 1);
X
X if (prefix) {
X fputs(prefix, t);
X fputc(' ', t);
X }
X
X fputs(subj, t);
X fputc(NL, t);
X
X ed_line++;
X return 1;
X}
X
X
Xstatic ng_line(t)
XFILE *t;
X{
X fprintf(t, "Newsgroups: %s\n",
X news.ng_follow ? news.ng_follow : news.ng_groups);
X ed_line++;
X}
X
Xstatic ref_line(t)
XFILE *t;
X{
X if (news.ng_ref == NULL && news.ng_ident == NULL) return;
X
X fputs("References:", t);
X if (news.ng_ref) fprintf(t, " %s", news.ng_ref);
X if (news.ng_ident) fprintf(t, " %s", news.ng_ident);
X putc(NL, t);
X ed_line++;
X}
X
X
Xstatic to_line(t, to)
XFILE *t;
Xchar *to;
X{
X if (to == NULL) return 0;
X
X fprintf(t, "To: %s\n", to);
X ed_line++;
X return 1;
X}
X
Xstatic alt_to_line(t, to)
XFILE *t;
Xchar *to;
X{
X if (to == NULL) return;
X
X fprintf(t, "Orig-To: %s\n", to);
X ed_line++;
X}
X
Xstatic end_header(t)
XFILE *t;
X{
X fputc(NL, t);
X ed_line++;
X}
X
X
Xstatic reply_to(t, address)
XFILE *t;
Xchar *address;
X{
X char route[512];
X
X if (address == NULL) return 0;
X
X if (reroute(route, address)) {
X to_line(t, route);
X return 1;
X }
X return 0;
X}
X
X
X/*
X * invoke aux shell script with suitable arguments
X *
X * WARNING: record may be NULL, soit must be the last argument!!
X */
X
Xstatic aux_sh(prog, action, record, not_sent)
Xchar *prog, *action, *record, *not_sent;
X{
X char *args[8];
X char number[10];
X register char **ap = args;
X time_t start_t;
X
X *ap++ = "nnaux";
X *ap++ = relative(lib_directory, "aux");
X *ap++ = prog;
X
X if (ed_line >= 0) { /* not cancel */
X sprintf(number, "%d", ed_line);
X *ap++ = temp_file;
X *ap++ = number;
X }
X
X *ap++ = action; /* article id for cancel */
X *ap++ = record; /* group name for cancel */
X
X *ap++ = NULL;
X
X#ifdef STATISTICS
X time(&start_t);
X#endif
X if (execute(SHELL, args)) {
X prompt_line = -1;
X prompt("\1%s\1", not_sent);
X sleep(1);
X return 1;
X }
X
X#ifdef STATISTICS
X tick_usage((time_t *)NULL, &start_t);
X#endif
X
X return 0;
X}
NO_NEWS_IS_GOOD_NEWS
chmod 0644 answer.c || echo "restore of answer.c fails"
set `wc -c answer.c`;Sum=$1
if test "$Sum" != "9895"
then echo original size 9895, current size $Sum;fi
echo "x - extracting articles.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > articles.c &&
X/*
X * access - get access to master data
X */
X
X#include "config.h"
X#include "db.h"
X#include "articles.h"
X#include "match.h"
X
X
X/*
X * memory management
X */
X
Xstatic thunk
X dummy_str_t = {
X NULL,
X NULL,
X 0L
X },
X dummy_art_t = {
X NULL,
X NULL,
X 0L
X };
X
X
Xstatic thunk *first_str_t = &dummy_str_t;
Xstatic thunk *current_str_t = &dummy_str_t;
Xstatic thunk *first_art_t = &dummy_art_t;
Xstatic thunk *current_art_t = &dummy_art_t;
Xstatic int cur_str_size = 0, cur_art_size = 0;
Xstatic char *next_str;
Xstatic article_header *next_art, **art_array;
X
Xstatic unsigned max_articles = 0, mem_offset = 0;
X
X/*
X * allocate one article header
X */
X
X#ifndef ART_THUNK_SIZE
X#define ART_THUNK_SIZE 127
X#endif
X
Xstatic new_thunk(t, ptr, size, chk_msg)
Xthunk *t;
Xchar *ptr;
Xlong size;
Xchar *chk_msg;
X{
X thunk *new;
X
X mem_check(ptr, (int)size, chk_msg);
X
X new = (thunk *)calloc(1, sizeof(thunk));
X mem_check(new, sizeof(thunk), "memory thunk");
X
X new->next_thunk = t->next_thunk;
X t->next_thunk = new;
X
X new->this_thunk = ptr;
X new->thunk_size = size;
X}
X
X
Xarticle_header *alloc_art()
X{
X if (cur_art_size == 0) {
X if (current_art_t->next_thunk == NULL)
X new_thunk(current_art_t,
X calloc(ART_THUNK_SIZE, sizeof(article_header)),
X (long)ART_THUNK_SIZE,
X "article headers");
X
X current_art_t = current_art_t->next_thunk;
X next_art = (article_header *)current_art_t->this_thunk;
X cur_art_size = current_art_t->thunk_size;
X }
X
X cur_art_size--;
X return next_art++;
X}
X
X/*
X * allocate a string of length 'len'
X */
X
X#ifndef STR_THUNK_SIZE
X#define STR_THUNK_SIZE ((1<<14) - 32) /* leave room for malloc header */
X#endif
X
Xchar *alloc_str(len)
Xint len;
X{
X char *ret;
X
X if (cur_str_size <= len) { /* must be room for len+1 bytes */
X if (current_str_t->next_thunk == NULL)
X new_thunk(current_str_t,
X malloc(STR_THUNK_SIZE),
X STR_THUNK_SIZE,
X "string bytes");
X
X current_str_t = current_str_t->next_thunk;
X next_str = current_str_t->this_thunk;
X cur_str_size = current_str_t->thunk_size;
X }
X
X ret = next_str;
X cur_str_size -= len + 1;
X next_str += len;
X *next_str++ = NUL; /* string is null terminated */
X
X return ret;
X}
X
X/*
X * "free" the allocated memory
X */
X
Xfree_memory()
X{
X current_str_t = first_str_t;
X current_art_t = first_art_t;
X cur_str_size = 0;
X cur_art_size = 0;
X n_articles = 0;
X}
X
X
X/*
X * mark/release memory
X */
X
X
Xmark_str(str_marker)
Xstring_marker *str_marker;
X{
X str_marker->sm_cur_t = current_str_t;
X str_marker->sm_size = cur_str_size;
X str_marker->sm_next = next_str;
X}
X
Xrelease_str(str_marker)
Xstring_marker *str_marker;
X{
X current_str_t = str_marker->sm_cur_t;
X cur_str_size = str_marker->sm_size;
X next_str = str_marker->sm_next;
X}
X
X
Xmark_memory(mem_marker)
Xmemory_marker *mem_marker;
X{
X mark_str(&(mem_marker->mm_string));
X
X mem_marker->mm_cur_t = current_art_t;
X mem_marker->mm_size = cur_art_size;
X mem_marker->mm_next = next_art;
X
X mem_marker->mm_nart = n_articles;
X mem_offset += n_articles;
X
X n_articles = 0;
X articles = art_array + mem_offset;
X}
X
Xrelease_memory(mem_marker)
Xmemory_marker *mem_marker;
X{
X release_str(&(mem_marker->mm_string));
X
X current_art_t = mem_marker->mm_cur_t;
X cur_art_size = mem_marker->mm_size;
X next_art = mem_marker->mm_next;
X
X n_articles = mem_marker->mm_nart;
X
X mem_offset -= n_articles;
X articles = art_array + mem_offset;
X}
X
X/*
X * merge all memory chunks into one.
X */
X
Xmerge_memory()
X{
X n_articles += mem_offset;
X mem_offset = 0;
X articles = art_array;
X}
X
X
X/*
X * save article header in 'articles' array
X * 'articles' is enlarged if too small
X */
X
X#define FIRST_ART_ARRAY_SIZE 500 /* malloc header */
X#define NEXT_ART_ARRAY_SIZE 512
X
Xadd_article(art)
Xarticle_header *art;
X{
X register long n;
X
X if ((n_articles + mem_offset) == max_articles) {
X /* must increase size of 'articles' */
X
X if (max_articles == 0) {
X /* allocate initial 'articles' array */
X max_articles = FIRST_ART_ARRAY_SIZE;
X n = 0;
X } else {
X new_thunk(current_str_t,
X (char *)art_array,
X (long)(max_articles*sizeof(article_header **)),
X "");
X n = max_articles;
X articles = art_array + n;
X
X max_articles += NEXT_ART_ARRAY_SIZE;
X }
X art_array = (article_header **)
X calloc(max_articles, sizeof(article_header **));
X mem_check(art_array, (int)max_articles, "article headers");
X while (--n >= 0) art_array[n] = *--articles;
X articles = art_array + mem_offset;
X }
X
X articles[n_articles] = art;
X n_articles++;
X}
X
X
Xstatic char match_subject[128] = {
X
X/* NUL SOH STX ETX EOT ENQ ACK BEL BS TAB NL VT FF CR SO SI */
X 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
X
X/* DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US */
X 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00,
X
X/* SP ! " # $ % & ' ( ) * + , - . / */
X 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 99, 00, 00, 00, 00,
X/* ^^ */
X
X/* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
X 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 00, 00, 00, 00, 00, 00,
X
X/* @ A B C D E F G H I J K L M N O */
X 00, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
X
X/* P Q R S T U V W X Y Z [ \ ] ^ _ */
X 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 00, 00,
X
X/* ` a b c d e f g h i j k l m n o */
X 00, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
X
X/* p q r s t u v w x y z { | } ~ DEL */
X 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 00, 00
X
X};
X
X
Xstatic article_comp(ah1, ah2)
Xarticle_header **ah1, **ah2;
X{
X register char *a = (**ah1).subject, *b = (**ah2).subject;
X register p;
X
X for (;; a++, b++) {
X while (*a && MATCH_DROP(match_subject, *a)) a++;
X while (*b && MATCH_DROP(match_subject, *b)) b++;
X if (*a == NUL) {
X if (*b) return -1;
X break;
X }
X if (*b == NUL) return 1;
X if (p = MATCH_CMP(match_subject, *a, *b)) return p;
X }
X/*
X if (p = (**ah1).replies - (**ah2).replies) return p;
X */
X if ((**ah1).t_stamp > (**ah2).t_stamp) return 1;
X if ((**ah1).t_stamp == (**ah2).t_stamp) return 0;
X return -1;
X}
X
X
Xstatic article_equal(ah1, ah2) /* ah1.hdr == ah2.hdr */
Xarticle_header **ah1, **ah2;
X{
X register char *a = (**ah1).subject, *b = (**ah2).subject;
X
X for (;; a++, b++) {
X while (*a && MATCH_DROP(match_subject, *a)) a++;
X while (*b && MATCH_DROP(match_subject, *b)) b++;
X if (*a == NUL) {
X if (*b == NUL) break;
X goto not_equal;
X }
X if (*b == NUL) goto not_equal;
X if (MATCH_EQ(match_subject, *a, *b)) continue;
X goto not_equal;
X }
X
X return 1;
X
X not_equal:
X return 0;
X}
X
X
Xsort_articles()
X{
X register article_header **app;
X register long n;
X
X if (n_articles <= 1) return;
X
X qsort(articles, n_articles, sizeof(article_header *), article_comp);
X
X for (n = n_articles - 1, app = articles + 1; --n >= 0; app++)
X if (article_equal(app, app - 1)) (**app).flag |= A_SAME;
X}
X
X
Xstatic offset_cmp(a, b)
Xarticle_header **a, **b;
X{
X register i;
X
X if (i = (int)((*a)->a_number - (*b)->a_number))
X return i;
X
X return (int)((*a)->fpos - (*b)->fpos);
X}
X
Xstatic age_cmp(ah1, ah2)
Xarticle_header **ah1, **ah2;
X{
X if ((**ah1).t_stamp > (**ah2).t_stamp) return 1;
X if ((**ah1).t_stamp == (**ah2).t_stamp) return 0;
X return -1;
X}
X
X
Xunsort_articles(arrival)
X{
X register int i;
X
X for (i = n_articles; --i >= 0;)
X articles[i]->flag &= ~A_SAME;
X
X if (n_articles <= 1) return;
X qsort(articles, n_articles, sizeof(article_header *),
X arrival ? offset_cmp : age_cmp);
X}
X
NO_NEWS_IS_GOOD_NEWS
chmod 0644 articles.c || echo "restore of articles.c fails"
set `wc -c articles.c`;Sum=$1
if test "$Sum" != "7942"
then echo original size 7942, current size $Sum;fi
echo "x - extracting articles.h (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > articles.h &&
X/*
X * memory handling
X */
X
X/* article headers */
X
Xarticle_number n_articles;
Xarticle_header **articles;
X
X/* number of articles killed by last access_group call */
X
Xint killed_articles;
X
Xtypedef struct thunk {
X char *this_thunk;
X struct thunk *next_thunk;
X long thunk_size;
X} thunk;
X
X
Xtypedef struct {
X thunk *sm_cur_t;
X int sm_size;
X char *sm_next;
X} string_marker;
X
X
Xtypedef struct {
X string_marker mm_string;
X thunk *mm_cur_t;
X int mm_size;
X article_header *mm_next;
X long mm_nart;
X} memory_marker;
X
X
Xextern article_header *alloc_art();
Xextern char *alloc_str();
NO_NEWS_IS_GOOD_NEWS
chmod 0644 articles.h || echo "restore of articles.h fails"
set `wc -c articles.h`;Sum=$1
if test "$Sum" != "611"
then echo original size 611, current size $Sum;fi
echo "x - extracting aux.sh (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > aux.sh &&
X
X# CONFIG is inserted above this line during INSTALL
X
Xtrap : 2 3
X
XPATH=/bin:$PATH
Xexport PATH
X
X# first argument is operation to be performed:
X# when saved, we shift it off
X
XOPERATION=$1
Xshift
X
X
X# first we handle 'cancel'
X# $1 is ident, $2 is group name.
X
Xif [ "$OPERATION" = "cancel" ] ; then
X $INEWS -t 'cmsg cancel '"$1" -n "$2" < /dev/null > /tmp/nn$$c 2>&1
X x=$?
X if [ $x != 0 ]; then
X echo ''
X cat /tmp/nn$$c
X sleep 2
X fi
X rm -f /tmp/nn$$c
X exit $x
Xfi
X
XWORK="$1"
XED_LINE="$2"
XFIRST_ACTION="$3"
XRECORD="$4"
X
XTRACE=${WORK}T
XCOPY=""
X
Xif [ "${FIRST_ACTION}" = "edit" ] ; then
X COPY=${WORK}C
X cp $WORK $COPY
Xfi
X
X# loop until sent or aborted.
X
Xloop=true
Xprompt=false
Xwhile $loop ; do
X if $prompt ; then
X echo ''
X awk 'END{printf "Action: (a)bort (e)dit (o)k (s)end: "}' < /dev/null
X read act
X else
X act="${FIRST_ACTION}"
X prompt=true
X fi
X
X case $act in
X a*)
X rm -f $WORK $COPY
X exit 22
X ;;
X e*)
X # call editor to enter at line $2 of work file
X
X case `basename "${EDITOR-vi}"` in
X vi|emacs )
X # Berkeley vi display editor
X # GNU emacs disply editor
X ${EDITOR-vi} +${ED_LINE} $WORK
X ;;
X ded )
X # QMC ded display editor
X $EDITOR -l${ED_LINE} $WORK
X ;;
X uemacs )
X # micro emacs
X $EDITOR -g${ED_LINE} $WORK
X ;;
X * )
X # Unknown editor
X $EDITOR $WORK
X ;;
X esac
X ;;
X
X o*|s*)
X loop=false
X ;;
X
X esac
Xdone
X
Xif [ -n "$COPY" ] ; then
X if [ -s $WORK ] ; then
X if cmp -s $WORK $COPY ; then
X rm -f $WORK $COPY
X exit 22
X fi
X else
X rm -f $WORK $COPY
X exit 22
X fi
X
X rm -f $COPY
Xfi
X
Xcase "$OPERATION" in
Xreply|forward|mail)
X if $APPENDSIG ; then
X if [ -f $HOME/.signature ] ; then
X awk 'END{printf "Append .signature? (y) : "}' < /dev/null
X read ans
X case $ans in
X ''|y*|Y*)
X echo "--" >> $WORK
X cat $HOME/.signature >> $WORK
X ;;
X esac
X fi
X fi
X ;;
Xfollow|post)
X echo "Be patient! Your new article will not show up immediately."
X sleep 2
X ;;
Xesac
X
X{
X trap 'echo SIGNAL' 1 2 3
X
X case "$OPERATION" in
X
X reply|forward|mail)
X grep -v "^Orig-To: " $WORK | $RECMAIL
X x=$?
X ;;
X
X follow|post)
X grep -v "^Orig-To: " $WORK | $INEWS -h
X x=$?
X # wait for inews to finish
X sleep 60
X ;;
X
X *)
X echo "Invalid operation: $OPERATION -- help"
X OPERATION="nn response operation"
X x=1
X cat > /dev/null
X ;;
X
X esac > $TRACE 2>&1
X
X
X if [ 0"$x" -ne 0 -o -s $TRACE ] ; then
X if [ -s $HOME/dead.letter ] ; then
X cat $HOME/dead.letter >> $HOME/dead.letters
X echo '' >> $HOME/dead.letters
X fi
X grep -v "^Orig-To: " $WORK > $HOME/dead.letter
X {
X echo "To: ${LOGNAME-$USER}"
X echo "Subject: $OPERATION failed"
X echo ''
X cat $TRACE
X echo ''
X echo 'Your response has been saved in ~/dead.letter'
X echo ''
X echo 'Your article/letter follows:'
X cat $WORK
X } | $RECMAIL
X
X elif [ -n "${RECORD}" ] ; then
X {
X # keep a copy of message in $RECORD (in mail format)
X set `date`
X if [ $3 -gt 9 ] ; then
X echo From ${LOGNAME-$USER} $1 $2 $3 $4 $6 $7
X else
X echo From ${LOGNAME-$USER} $1 $2 ' '$3 $4 $6 $7
X fi
X echo "From: ${LOGNAME-$USER}"
X grep -v '^Orig-To: ' $WORK
X echo ''
X } >> "$RECORD"
X fi
X
X rm -f $WORK $TRACE
X
X} > /dev/null 2>&1 &
X
Xexit 0
NO_NEWS_IS_GOOD_NEWS
chmod 0644 aux.sh || echo "restore of aux.sh fails"
set `wc -c aux.sh`;Sum=$1
if test "$Sum" != "3107"
then echo original size 3107, current size $Sum;fi
echo "x - extracting back_act.sh (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > back_act.sh &&
X# prefix is inserted above by make
X
X#
X# back_act will maintain a set of `old' active files
X# in the DB directory where they can be used by nngoback
X# to backtrack the rc file a number of days.
X#
X# It should be invoked by cron every day at midnight.
X# It should run as user `news'!
X#
X
Xcd $DB || exit 1
X
Xp=15
Xl=""
Xfor i in 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Xdo
X if [ -f active.$i ]
X then
X mv active.$i active.$p
X l=$p
X elif [ -n "$l" ]
X then
X ln active.$l active.$p
X fi
X p=$i
Xdone
X
Xcp $ACTIVE active.0
Xchmod 644 active.0
NO_NEWS_IS_GOOD_NEWS
chmod 0644 back_act.sh || echo "restore of back_act.sh fails"
set `wc -c back_act.sh`;Sum=$1
if test "$Sum" != "522"
then echo original size 522, current size $Sum;fi
echo "x - extracting collect.c (Text)"
sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > collect.c &&
X#include "config.h"
X#include "db.h"
X#include "news.h"
X
Ximport int trace;
X
X
Xstatic FILE *ix, *data;
X
X/*
X * Collect unread articles in current group
X *
X * On entry, init_group has been called to setup the proper environment
X */
X
Xcollect_group(gh)
Xregister group_header *gh;
X{
X int article_count, temp;
X article_number start_collect;
X
X if (gh->last_l_article == 0) {
X gh->first_l_article = gh->first_article;
X gh->last_l_article = gh->first_l_article - 1;
X }
X
X if (gh->last_l_article >= gh->last_article) return 0;
X
X if (gh->index_write_offset) {
X ix = open_data_file(gh, 'x', OPEN_UPDATE|MUST_EXIST);
X fseek(ix, gh->index_write_offset, 0);
X } else
X ix = open_data_file(gh, 'x', OPEN_CREATE|MUST_EXIST);
X
X if (gh->data_write_offset) {
X data = open_data_file(gh, 'd', OPEN_UPDATE|MUST_EXIST);
X fseek(data, gh->data_write_offset, 0);
X } else
X data = open_data_file(gh, 'd', OPEN_CREATE|MUST_EXIST);
X
X article_count = 0;
X start_collect = gh->last_l_article+1;
X
X while (gh->last_l_article < gh->last_article) {
X if (s_hangup) break;
X gh->last_l_article++;
X gh->data_write_offset = ftell(data);
X#ifdef NNTP
X gh->index_write_offset = ftell(ix);
X#endif
X if (!db_write_offset(ix, &(gh->data_write_offset)))
X write_error();
X
X temp = collect_article(gh, gh->last_l_article);
X#ifdef NNTP
X if (temp < 0) {
X /* connection failed, current article is not collected */
X gh->last_l_article--;
X article_count = -1;
X goto out;
X }
X#endif
X article_count += temp;
X }
X
X if (trace && start_collect <= gh->last_l_article) {
X log_entry('T', "Col %s (%d to %d) %d",
X gh->group_name,
X start_collect, gh->last_l_article,
X article_count);
X fl;
X }
X
X gh->data_write_offset = ftell(data);
X gh->index_write_offset = ftell(ix);
X
X out:
X fclose(data);
X fclose(ix);
X
X return article_count;
X}
X
X
Xstatic data_header hdr;
X
X
Xstatic collect_article(gh, art_num)
Xregister group_header *gh;
Xarticle_number art_num;
X{
X FILE *art_file;
X news_header_buffer nhbuf, dgbuf;
X article_header art_hdr;
X int mode, count;
X cross_post_number cross_post_table[256], *cp_ptr;
X count = 0;
X
X hdr.dh_number = art_num;
X
X /* get article header */
X
X art_hdr.a_number = art_num;
X art_hdr.hpos = (off_t)0;
X art_hdr.lpos = (off_t)0;
X
X mode = FILL_NEWS_HEADER | FILL_OFFSETS | SKIP_HEADER;
X if ((gh->group_flag & (G_CONTROL | G_NEVER_DIGEST | G_ALWAYS_DIGEST)) == 0)
X mode |= DIGEST_CHECK;
X
X if ((art_file = open_news_article(&art_hdr, mode, nhbuf, (char *)NULL)) == NULL) {
X
X#ifdef NNTP
X import nntp_failed;
X
X if (nntp_failed) {
X /*
X * connection to nntp_server is broken
X * stop collection of articles immediately
X */
X return -1;
X }
X#endif
X /*
X * it is not really necessary to save anything in the data file
X * we simply use the index file to get the *first* available article
X */
X return 1; /* but we have still collected one article */
X }
X
X /* map cross-postings into a list of group numbers */
X
X hdr.dh_cross_postings = 0;
X
X if (gh->group_flag & G_CONTROL) {
X /* we cannot trust the Newsgroups: line in the control group */
X /* so we simply ignore it (i.e. use "Newsgroups: control") */
X goto dont_digest;
X }
X
X if (news.ng_groups) {
X char *curg, *nextg;
X group_header *gh1;
X
X for (nextg = news.ng_groups, cp_ptr = cross_post_table; *nextg; ) {
X curg = nextg;
X
X if (nextg = strchr(curg, ','))
X *nextg++ = NUL;
X else
X nextg = "";
X
X if (strcmp(gh->group_name, curg) == 0) break;
X
X if ((gh1 = lookup(curg)) == NULL) continue;
X
X *cp_ptr++ = gh1->group_num;
X hdr.dh_cross_postings++;
X }
X }
X
X if (gh->group_flag & G_NEVER_DIGEST)
X goto dont_digest;
X
X /* split digest */
X
X
X if ((gh->group_flag & G_ALWAYS_DIGEST) || (news.ng_flag & N_DIGEST)) {
X int any = 0, cont = 1;
X
X skip_digest_body(art_file);
X
X while (cont && (cont = get_digest_article(art_file, dgbuf)) >= 0) {
X
X if (any == 0) {
X /* write DIGEST_HEADER */
X build_hdr(2, -art_num, cross_post_table);
X count++;
X
X hdr.dh_cross_postings = 0; /* no cross post in sub */
X any++;
X }
X /* write SUB_DIGEST */
X build_hdr(1, (article_number)0, (group_number *)NULL);
X count++;
X }
X
X if (any) goto finish;
X }
X
X /* not a digest */
X
X dont_digest:
X
X build_hdr(0, art_num, cross_post_table); /* normal article */
X count++;
X
Xfinish:
X
X fclose(art_file);
X
X return count;
X}
X
X
Xstatic build_hdr(use_digest, art_num, cross_post_table)
Xint use_digest;
Xarticle_number art_num;
Xcross_post_number *cross_post_table;
X{
X register char *name, *subj;
X char name_buf[NAME_LENGTH+1], subj_buf[256];
X int re;
X
X if (use_digest & 1) {
X
X name = digest.dg_from;
X subj = digest.dg_subj;
X
X hdr.dh_lines = digest.dg_lines;
X
X hdr.dh_hpos = digest.dg_hpos;
X hdr.dh_fpos = (int16)(digest.dg_fpos - hdr.dh_hpos);
X hdr.dh_lpos = digest.dg_lpos;
X
X pack_date(&(hdr.dh_date),
X digest.dg_date ? digest.dg_date : news.ng_date);
X } else {
X
X if (!news.ng_from) news.ng_from = news.ng_reply;
X
X name = news.ng_from;
X subj = news.ng_subj;
X
X hdr.dh_lines = news.ng_lines;
X
X hdr.dh_hpos = 0;
X hdr.dh_fpos = (int16)(news.ng_fpos);
X hdr.dh_lpos = news.ng_lpos;
X
X pack_date(&(hdr.dh_date), news.ng_date);
X }
X
X hdr.dh_number = art_num;
X
X /* pack name and write on .nn2 */
X
X if (name) {
X hdr.dh_sender_length = pack_name(name_buf, name, NAME_LENGTH);
X } else
X hdr.dh_sender_length = 0;
X
X /* write subject line on .nn2 */
X
X hdr.dh_subject_length = pack_subject(subj_buf, subj, &re, 255);
X hdr.dh_replies = re;
X
X if (use_digest & 2) hdr.dh_subject_length++; /* @ */
X
X /* WRITE hdr, cross postings, name, subject */
X
X db_write_art(data, &hdr);
X
X if (cross_post_table && hdr.dh_cross_postings) {
X#ifdef NETWORK_DATABASE
X#ifndef NETWORK_BYTE_ORDER
X int i;
X
X for (i = 0; i < hdr.dh_cross_postings; i++)
X cross_post_table[i] = htonl(cross_post_table[i]);
X#endif
X#endif
X Fwrite((char *)cross_post_table, sizeof(cross_post_number),
X (int)hdr.dh_cross_postings, data);
X }
X
X if (hdr.dh_sender_length)
X Fwrite(name_buf, sizeof(char), (int)hdr.dh_sender_length, data);
X
X if (use_digest & 2) {
NO_NEWS_IS_GOOD_NEWS
echo "End of part 2"
echo "File collect.c is continued in part 3"
echo "3" > s2_seq_.tmp
exit 0
---
Kim F. Storm storm at texas.dk Tel +45 429 174 00
Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
No news is good news, but nn is better!
--
Please send comp.sources.unix-related mail to rsalz at uunet.uu.net.
Use a domain-based address or give alternate paths, or you may lose out.
More information about the Comp.sources.unix
mailing list