home *** CD-ROM | disk | FTP | other *** search
- Subject: v19i063: NN, a Usenet news reader, Part02/15
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: storm@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@texas.dk Tel +45 429 174 00
- Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
- No news is good news, but nn is better!
-
-