This is an official patch to nn release 6.4 ------------------------------------------- PATCH #10 Priority: HIGH NOTICE: As descibed below one or two parts of this patch may be rejected by the "patch" program - if this happens to you, read the following description to see if you need to care (usually you don't!) This patch fixes problems with 64k segment limitations on 286 based systems, a realloc error which could cause the nnmaster to crash as new groups are created, a bug in handling of aliased groups, some problems with missing Distribution: headers fooling Cnews, and ONE BIG BLUNDER in the mini-inews supplied with nn's initial release: =================================================================== When the mini-inews supplied with nn 6.4 is used, but the DOMAIN in conf.h has not been changed as required (and that is easy to over- look), all postings will look like they came from "iti.org" - and Steve Simmons is getting pretty tired of all the bounced mail for users unknown to iti. To fix this, inews/conf.h is patched to contain an invalid domain name. IF YOU HAVE MADE THE REQUIRED CHANGE TO THE DEFINITION OF DOMAIN IN inews/conf.h THIS PATCH WILL *FAIL* ON THE PART RELATED TO THAT FILE. You can safely ignore this rejected patch since you have already done what is required to "fix" the problem. ====================================================================== A syntax error in s-fortune.h is also fixed by this patch; if you are using that file now, you probably already fixed the bug, so that part of the patch is likely to fail as well - or worse, it may silently reintroduce the bug be reverting your own patch (the "patch" program is pretty stupid in that respect). =================================================================== When posting (also follow-ups) nn will now *always* generate a Distribution: header line, and the default distribution is now explicitly "world" (which is the implicit meaning of no Distribution in Bnews, but not in Cnews). The facilities to control this are two new variables post-distribution and follow-distribution, and a change to the use of default-distribution. This is *not* documented in this patch, but the default values of the new variables will make everything work as usual. =================================================================== As usual, all changes are described in the updated RELEASE_NOTES file (read that for more details about this patch). Thanks to all who reported bugs and provided fixes. To apply this patch, use nn's :patch command, or run this command from the shell in the root of the nn source tree: patch -p0 < this-article Then run "make all" and "./inst u". ++Kim Storm *** ./LAST/active.c Tue May 22 12:53:32 1990 --- active.c Tue Sep 11 17:53:18 1990 *************** *** 90,103 **** break; case '=': - gh->master_flag |= M_ALIASED | M_IGNORE_A; - if (old_flag & M_ALIASED) continue; while (*++cp && isspace(*cp)) cp++; name = cp; while (*cp && !isspace(*cp)) cp++; *cp = NUL; ! gh1 = lookup(name); ! gh->data_write_offset = (off_t)gh1->group_num; must_update = 1; break; } --- 90,123 ---- break; case '=': while (*++cp && isspace(*cp)) cp++; name = cp; while (*cp && !isspace(*cp)) cp++; *cp = NUL; ! if (old_flag & M_ALIASED) { ! /* quick check: has the alias changed */ ! int32 n = (int32)gh->data_write_offset; ! if (n >= 0 && n < master.number_of_groups) { ! gh1 = ACTIVE_GROUP(n); ! if (strcmp(gh1->group_name, name) == 0) { ! gh->master_flag |= M_ALIASED | M_IGNORE_A; ! continue; ! } ! } ! } ! gh1 = lookup_no_alias(name); ! if (gh1 == NULL) { ! /* '=unknown.group' is treated just like 'x' */ ! if ((old_flag & M_IGNORE_A) == 0) ! log_entry('R', "Group %s aliased to unknown group (%s)", ! gh->group_name, name); ! gh->master_flag |= M_IGNORE_A; ! if ((old_flag & (M_IGNORE_A|M_ALIASED)) == M_IGNORE_A) ! continue; ! } else { ! gh->master_flag |= M_ALIASED | M_IGNORE_A; ! gh->data_write_offset = (off_t)gh1->group_num; ! } must_update = 1; break; } *** ./LAST/admin.c Mon Jul 16 17:38:39 1990 --- admin.c Thu Sep 6 20:23:04 1990 *************** *** 191,198 **** articles = disk_use = 0; nblocked = nignored = 0; ! for (cur_group = 0; cur_group < master.number_of_groups; cur_group++) { ! gh = &active_groups[cur_group]; #define DISK_BLOCKS(bytes) (((bytes) + 1023) / 1024) --- 191,197 ---- articles = disk_use = 0; nblocked = nignored = 0; ! Loop_Groups_Header(gh) { #define DISK_BLOCKS(bytes) (((bytes) + 1023) / 1024) *************** *** 564,570 **** cur_group = (int)get_entry("Group number", 0L, (long)(master.number_of_groups - 1)); if (cur_group >= 0) ! dump_m_entry(&active_groups[cur_group]); break; case 'D': --- 563,569 ---- cur_group = (int)get_entry("Group number", 0L, (long)(master.number_of_groups - 1)); if (cur_group >= 0) ! dump_m_entry(ACTIVE_GROUP(cur_group)); break; case 'D': *************** *** 572,584 **** c = get_cmd( "\nA)ll B)locked E)mpty H)oles I)gnored N)on-empty V)alid in(W)alid", "DUMP"); - cur_group = -1; pg_init(1, 1); ! while (++cur_group < master.number_of_groups) { if (s_keyboard || s_hangup) break; - - gh = &active_groups[cur_group]; #define NODUMP(cond) if (cond) continue; break switch (c) { case 'N': --- 571,580 ---- c = get_cmd( "\nA)ll B)locked E)mpty H)oles I)gnored N)on-empty V)alid in(W)alid", "DUMP"); pg_init(1, 1); ! Loop_Groups_Header(gh) { if (s_keyboard || s_hangup) break; #define NODUMP(cond) if (cond) continue; break switch (c) { case 'N': *************** *** 595,600 **** --- 591,598 ---- NODUMP((gh->master_flag & M_VALID) == 0); case 'W': NODUMP(gh->master_flag & M_VALID); + case 'A': + break; default: s_keyboard = 1; continue; } *** ./LAST/answer.c Thu Jul 19 18:12:10 1990 --- answer.c Mon Sep 17 14:50:08 1990 *************** *** 14,20 **** extern char *temp_file; extern char *news_lib_directory; ! export char *default_distribution = NULL; export char *extra_mail_headers = NULL; export char *extra_news_headers = NULL; export char *mail_record = NULL; --- 14,26 ---- extern char *temp_file; extern char *news_lib_directory; ! #ifndef DEFAULT_DISTRIB ! #define DEFAULT_DISTRIB "world" ! #endif ! ! export char *default_distribution = DEFAULT_DISTRIB; ! export char *distribution_follow = "always same default"; ! export char *distribution_post = "ask default"; export char *extra_mail_headers = NULL; export char *extra_news_headers = NULL; export char *mail_record = NULL; *************** *** 405,410 **** --- 411,448 ---- fclose(s); } + static char *get_distr(orig, distr) + char *orig, *distr; + { + flag_type opts; + int always, ask, same, dflt; + char *str, *dd; + + if ((dd = default_distribution) == NULL) dd = DEFAULT_DISTRIB; + + if (distr == NULL) distr = "default"; + var_options(&distr, "always\0ask\0same\0default\0", &opts); + always = (opts & FLAG(0)); + ask = (opts & FLAG(1)); + same = (opts & FLAG(2)); + dflt = (opts & FLAG(3)); + + if (*distr == NUL || dflt) distr = dd; + + if (same && orig != NULL) { + distr = orig; + if (always) ask = 0; + } + + if (!ask) return distr; + + prompt("Distribution: (default '%s') ", distr); + str = get_s(NONE, NONE, NONE, NULL_FCT); + if (str == NULL) return NULL; + if (*str != NUL) distr = str; + return distr; + } + answer(ah, command, incl) article_header *ah; int command; *************** *** 542,551 **** ed_line++; } ! if (news.ng_dist) { ! fprintf(t, "Distribution: %s\n", news.ng_dist); ! ed_line++; ! } ref_line(t); --- 580,589 ---- ed_line++; } ! str = get_distr(news.ng_dist, distribution_follow); ! if (str == NULL) goto close_t; ! fprintf(t, "Distribution: %s\n", str); ! ed_line++; ref_line(t); *************** *** 911,933 **** } strcpy(summary, str); ! if (post_distribution) { ! strcpy(distribution, post_distribution); ! } else { ! if (default_distribution != NULL) ! strcpy(distribution, default_distribution); ! else { ! strcpy(distribution, group_name); ! if (str = strchr(distribution, ',')) *str = NUL; ! if (str = strchr(distribution, '.')) *str = NUL; ! } ! ! prompt("Distribution: (default '%s') ", distribution); ! str = get_s(NONE, NONE, NONE, NULL_FCT); if (str == NULL) goto no_post; - if (*str) strcpy(distribution, str); if (who_am_i == I_AM_POST) prompt_line++; } new_temp_file(); if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) { --- 949,960 ---- } strcpy(summary, str); ! if ((str = post_distribution) == NULL) { ! str = get_distr(NULL, distribution_post); if (str == NULL) goto no_post; if (who_am_i == I_AM_POST) prompt_line++; } + strcpy(distribution, str); new_temp_file(); if ((t = open_file(temp_file, OPEN_CREATE)) == NULL) { *** ./LAST/articles.c Thu Jul 19 18:12:10 1990 --- articles.c Fri Aug 31 14:11:04 1990 *************** *** 322,328 **** cross_post = NETW_CROSS_INT(db_data.dh_cross[n]); if (cross_post < 0 || cross_post >= master.number_of_groups) continue; ! cpgh = &active_groups[cross_post]; if (cpgh == gh) { if (seq_cross_filtering) continue; n = db_hdr.dh_cross_postings; --- 322,328 ---- cross_post = NETW_CROSS_INT(db_data.dh_cross[n]); if (cross_post < 0 || cross_post >= master.number_of_groups) continue; ! cpgh = ACTIVE_GROUP(cross_post); if (cpgh == gh) { if (seq_cross_filtering) continue; n = db_hdr.dh_cross_postings; *** ./LAST/conf/m-i80286.h Sat Mar 31 23:12:48 1990 --- conf/m-i80286.h Fri Aug 31 14:13:08 1990 *************** *** 13,18 **** --- 13,19 ---- typedef unsigned long uint32; /* 0 .. 2^31-1 */ #define I286_BUG + #define MALLOC_64K_LIMITATION #ifdef NETWORK_DATABASE *** ./LAST/conf/s-fortune.h Mon Apr 23 18:32:50 1990 --- conf/s-fortune.h Tue Aug 28 11:33:24 1990 *************** *** 1,4 **** - ******************************************************************* /* * This file is for Fortune 32:16 systems. * Use with m-m680x0.h file, but requires STRCSPN in config.h --- 1,3 ---- *** ./LAST/conf/s-uport2-2.h Mon Apr 23 18:32:44 1990 --- conf/s-uport2-2.h Thu Sep 6 19:47:42 1990 *************** *** 12,17 **** --- 12,19 ---- * Specify where the Bourne Shell is. */ + #define AVOID_SHELL_EXEC + #undef SHELL #define SHELL "/bin/ksh" *** ./LAST/db.c Mon Jul 16 17:38:40 1990 --- db.c Tue Sep 4 13:18:29 1990 *************** *** 13,19 **** --- 13,23 ---- import int db_data_subdirs; export master_header master; + #ifdef MALLOC_64K_LIMITATION + export group_header **active_groups = NULL; + #else export group_header *active_groups = NULL; + #endif export group_header **sorted_groups = NULL; export int reread_groups_file = 0; /* nnmaster -G */ *************** *** 391,396 **** --- 395,404 ---- } freeobj(sorted_groups); + #ifdef MALLOC_64K_LIMITATION + if (active_groups) + Loop_Groups_Header(gh) freeobj(gh); + #endif freeobj(active_groups); active_groups = NULL; sorted_groups = NULL; *************** *** 402,408 **** --- 410,422 ---- trust_master = (who_am_i != I_AM_MASTER || !reread_groups_file); db_sequential = 1; + #ifdef MALLOC_64K_LIMITATION + Loop_Groups_Number(l_g_index) { + gh = newobj(group_header, 1); + active_groups[l_g_index] = gh; + #else Loop_Groups_Header(gh) { + #endif gh->group_num = l_g_index; db_read_group(gh); db_parse_group(gh, trust_master); *************** *** 418,425 **** --- 432,447 ---- { master.free_groups = 20; + #ifdef MALLOC_64K_LIMITATION + active_groups = resizeobj(active_groups, group_header *, + master.number_of_groups + master.free_groups); + #else active_groups = resizeobj(active_groups, group_header, master.number_of_groups + master.free_groups); + clearobj(active_groups + master.number_of_groups, group_header, + master.free_groups); + #endif + sorted_groups = resizeobj(sorted_groups, group_header *, master.number_of_groups + master.free_groups); } *************** *** 502,514 **** char *name; { register group_header *gh; gh = lookup_no_alias(name); if (gh == NULL || (gh->master_flag & M_ALIASED) == 0) return gh; ! do ! gh = &active_groups[gh->data_write_offset]; ! while (gh->master_flag & M_ALIASED); return gh; } --- 524,551 ---- char *name; { register group_header *gh; + group_header *gh_na; + register int32 n, x; gh = lookup_no_alias(name); if (gh == NULL || (gh->master_flag & M_ALIASED) == 0) return gh; ! gh_na = gh; ! x = 16; ! do { ! if (--x == 0) { ! log_entry('R', "Possible alias loop: %s", name); ! return gh_na; ! } ! n = (int32)gh->data_write_offset; ! /* if alias info is unreliable, return original group ! which will be ignored anyway */ ! if (n < 0 || n >= master.number_of_groups) { ! log_entry('R', "Bad aliasing of %s -> %d", gh->group_name, n); ! return gh_na; ! } ! gh = ACTIVE_GROUP(n); ! } while (gh->master_flag & M_ALIASED); return gh; } *** ./LAST/doc/RELEASE_NOTES Thu Jul 19 18:12:11 1990 --- doc/RELEASE_NOTES Mon Sep 17 15:43:40 1990 *************** *** 535,540 **** --- 535,542 ---- Prog: nn Title: Unmark does not clear standout mode on HP terminals From: Bill Gaines + Hellmuth Michaelis + fix + Fixed: Patch #10 [term.c] On HP terminals, if you mark an article, and then unmark it, the inverse video highlight does not go away. You have to use "^L" to *************** *** 1049,1055 **** --- 1051,1169 ---- From: chuq@Apple.COM (The Bounty Hunter) Fixed: Patch #9 [menu.c more.c] + Prog: nnusage + Title: "nnusage -t" will print the header line last + From: asd@mace.cc.purdue.edu (Kareth) + fix + Fixed: Patch #10 [nnusage.sh] + Prog: nn + Title: motd file is shown on every invocation of nn + From: wilson@issun3.stc.nl (Tony Wilson) + A.C.G.Saunders@newcastle.ac.uk (Aidan Saunders) + Fixed: Patch #10 [nn.c] + + Prog: mini-inews + Title: Default DOMAIN was iti.org causing problems if people didn't change it. + From: scs@iti.org (Steve Simmons) + Fixed: Patch #10 [inews/conf.h] + + Prog: nn + Title: The support for the re-layout-read variable is not complete + From: gemini%geminix@tub.uucp (Uwe Doering) + fix + Fixed: Patch #10 [more.c] + + Prog: nnmaster + Title: May crash when new groups are created - group header is not cleared. + From: andrew@resam.dk (Leif Andrew Rump) + Remi Saccoman + fix + Fixed: Patch #10 [db.c global.c global.h] + + Prog: mkprefix (and shell scripts) + Title: /bin/sh is hardcoded in the #! line - SHELL should be used + From: asd@mace.cc.purdue.edu (Kareth) + fix + Fixed: Patch #10 [prefix.c] + + Prog: nn + From: news@m2xenix.psg.com (Randy Bush) + chl@cs.man.ac.uk (Charles Lindsey) + Title: new-group-action 5 does not work (crash on new group). + Fixed: Patch #10 [newsrc.c] + + Prog: nn + Title: nnmaster crashes if active file contains alias to non-existing group. + From: Mark Moraes + fix + jw@sics.se (Johan Widen) + Liz Allen-Mitchell + Fixed: Patch #10 [active.c db.c] + + Prog: nn + Title: "set boolean-var # comment" actually unsets boolean variable. + From: jeffy@teda.uucp (Who? Me?) + Fixed: Patch #10 [variable.c] + + Prog: nn + Title: Gould's preprocessor defines "sel" which breaks newsrc code + From: Eric Peterson + Fixed: Patch #10 [newsrc.c] + + Prog: all + Title: Cannot handle more than 650 groups on 80286 machines + From: John A. Limpert + tkevans@fallst.UUCP (Tim Evans) + Fixed: Patch #10 [admin.c articles.c db.c global.h kill.c master.c + m-i80286.h sequence.c] + + Prog: nnusage + Title: Option "-at" is not handled properly with ACCOUNTING on. + (+ all unknown options were passed directly to nnacct). + From: david@wraith.cs.uow.edu.au (David E A Wilson) + Fixed: Patch #10 [nnusage.sh] + + Prog: nn + Title: Duplicated articles on menu may have "-" entry before "subject" entry. + From: gemini%geminix@tub.uucp (Uwe Doering) + Fixed: Patch #10 [sort.c] + + Prog: nnmaster + Title: Removed groups are not "ignored" if they were empty. + From: Bernd Wechner + Fixed: Patch #10 [expire.c] + + Prog: nnadmin + Title: M)aster D)ump A)ll did not work + From: michi@ptcburp.ptcbu.oz.au (Michael Henning) + Fixed: Patch #10 [admin.c] + + Prog: nn manual + Title: delay-redraw variable was sometimes referenced as delayed-redraw + From: shj@login.dkuug.dk (Stig Jacobsen) + Fixed: Patch #10 [nn.1] + + Prog: nn + Title: group regexp entries in kill cannot have multiple patterns + From: asd@mace.cc.purdue.edu (Kareth) + Fixed: Patch #10 [kill.c] + + Prog: scripts + Title: uport must have AVOID_SHELL_EXEC defined. + From: John A. Limpert + Fixed: Patch #10 [s-uport2-2.h] + + Prog: nnmaster, nn + Title: From: line packing sometimes produces an empty name + From: Bernd Wechner + fix + Fixed: Patch #10 [pack_name.c] + + Prog: nn + Title: Ga only works some of the time (and really bad in reading mode) + From: David Lesher + Fixed: Patch #10 [group.c] + + In reading mode "Ga" silently expanded the level-1 menu rather + than giving a new level-2 menu - or if it gave a level-2 menu + it wasn't possible to repeat the command. + + New features since initial 6.4.0 release ---------------------------------------- *************** *** 1365,1367 **** --- 1479,1512 ---- Title: Variables can now be set on nn command line with var=value. From: KFS on request from asd@mace.cc.purdue.edu (Kareth) Added: Patch #9 [sequence.c] + + Prog: inst + Title: Patch level is now included in the installed manuals + From: Tim Rylance + Added: Patch #10 [inst.sh] + + Prog: nn + Title: New variable: also-full-digest to include full digest when split=on + From: KFS on request from Harry Herman + Added: Patch #10 [nn.c variable.c nn.1] + + Prog: nn + Title: "Searching..." is now shown while searching a pattern in an article + From: bernd@bhpcpd.kembla.oz.au (Bernd Wechner) + Added: Patch #10 [more.c] + + Prog: nn + Title: kill-debug is turned off if ^G or 'q' is used during debug output + From: KFS on request from iann@storesys.coles.oz.au (Ian Nicholls) + Added: Patch #10 [kill.c term.c] + + Prog: nn + Title: Made embedded-header-escape ('~') configureable + From: KFS on request from bernd@bhpcpd.kembla.oz.au (Bernd Wechner) + Added: Patch #10 [save.c variable.c nn.1] + + Prog: nn, nnpost + Title: Added post-distribution and follow-distribution variables to improve + generation of Distribution: headers. + From: KFS + Added: Patch #10 [answer.c variable.c] *** ./LAST/expire.c Thu Jul 19 18:12:12 1990 --- expire.c Wed Sep 5 13:24:05 1990 *************** *** 472,478 **** if (gh->master_flag & M_IGNORE_GROUP) continue; if ((gh->master_flag & M_VALID) == 0) { - if (gh->last_db_article == 0) continue; log_entry('X', "Group %s removed", gh->group_name); gh->master_flag |= M_IGNORE_A; clean_group(gh); --- 472,477 ---- *** ./LAST/global.c Thu Jul 19 18:12:12 1990 --- global.c Thu Sep 6 17:09:42 1990 *************** *** 740,745 **** --- 740,754 ---- return obj1; } + char *mem_clear(obj, size, nelt) + register char *obj; + unsigned size; + register int32 nelt; + { + nelt *= size; + while (--nelt >= 0) *obj++ = NUL; + } + mem_free(obj) char *obj; { *** ./LAST/global.h Mon Jun 25 15:46:41 1990 --- global.h Fri Aug 31 18:33:14 1990 *************** *** 177,182 **** --- 177,185 ---- #define resizeobj(obj, type, nelt) \ (type *)mem_resize((char *)(obj), sizeof(type), (int32)(nelt)) + #define clearobj(obj, type, nelt) \ + mem_clear((char *)(obj), sizeof(type), (int32)(nelt)) + #define freeobj(obj) mem_free((char *)(obj)) #define quicksort(a,n,t,f) qsort((char *)(a), (unsigned)(n), sizeof(t), f) *************** *** 192,198 **** --- 195,205 ---- /* group headers */ + #ifdef MALLOC_64K_LIMITATION + extern group_header **active_groups, **sorted_groups; + #else extern group_header *active_groups, **sorted_groups; + #endif /* current group information */ *************** *** 209,218 **** --- 216,233 ---- #define Loop_Groups_Number(num) \ for (num = 0; num < master.number_of_groups; num++) + #ifdef MALLOC_64K_LIMITATION + #define Loop_Groups_Header(gh) \ + for (l_g_index = 0; \ + (l_g_index < master.number_of_groups) && \ + (gh = active_groups[l_g_index]) ;\ + l_g_index++) + #else #define Loop_Groups_Header(gh) \ for (l_g_index = 0, gh=active_groups; \ l_g_index < master.number_of_groups; \ l_g_index++, gh++) + #endif #define Loop_Groups_Sorted(gh) \ for (l_g_index = s_g_first; \ *************** *** 225,230 **** --- 240,251 ---- #define Loop_Groups_Newsrc(gh) \ for (gh = rc_sequence; gh; gh = gh->newsrc_seq) + + #ifdef MALLOC_64K_LIMITATION + #define ACTIVE_GROUP(n) active_groups[n] + #else + #define ACTIVE_GROUP(n) &active_groups[n] + #endif /* 8 bit support (ISO 8859/...) */ *** ./LAST/group.c Thu Jul 19 18:12:13 1990 --- group.c Thu Sep 6 23:46:43 1990 *************** *** 114,119 **** --- 114,121 ---- } static int group_level = 0; + static article_number entry_first_article; + static int only_unread_articles; /* menu contains only unread art. */ static print_header() { *************** *** 133,141 **** if (no_update) { so_printf(" NO UPDATE"); } else { ! if (current_group->current_first > current_group->first_article + 1) so_printf((killed_articles > 0) ? "(L-%ld,K-%d)" : "(L-%ld)", ! current_group->current_first - current_group->first_article - 1, killed_articles); else if (killed_articles > 0) --- 135,144 ---- if (no_update) { so_printf(" NO UPDATE"); } else { ! if ((current_group->group_flag & G_MERGED) == 0 && ! current_group->current_first > entry_first_article) so_printf((killed_articles > 0) ? "(L-%ld,K-%d)" : "(L-%ld)", ! current_group->current_first - entry_first_article, killed_articles); else if (killed_articles > 0) *************** *** 183,191 **** --- 186,198 ---- register group_header *mg_head; flag_type entry_access_mode = access_mode; extern flag_type parse_access_flags(); + article_number o_entry_first; + int o_only_unread; #define menu_return(cmd) { menu_cmd = (cmd); goto menu_exit; } + o_entry_first = entry_first_article; + o_only_unread = only_unread_articles; o_killed = killed_articles; mark_var_stack(); *************** *** 257,262 **** --- 264,271 ---- } if (gh->current_first <= 0) gh->current_first = 1; + entry_first_article = gh->current_first; + only_unread_articles = (access_mode & ACC_ALSO_READ_ARTICLES) == 0; if (article_limit > 0) { n = gh->last_db_article - article_limit + 1; *************** *** 351,356 **** --- 360,367 ---- } while (mg_head != NULL && (gh = gh->merge_with) != NULL); killed_articles = o_killed; + entry_first_article = o_entry_first; + only_unread_articles = o_only_unread; restore_variables(); group_level--; *************** *** 430,435 **** --- 441,448 ---- extern article_header *get_menu_article(); extern int get_from_macro; extern group_header *jump_to_group; + article_number o_cur_first = -1; + group_header *read_mode_group; #define goto_return( cmd ) \ { menu_cmd = cmd; goto goto_exit; } *************** *** 438,443 **** --- 451,462 ---- gh = orig_group = current_group; + if (ah != NULL) { /* always open new level from reading mode */ + read_mode_group = orig_group; + orig_group = NULL; + } else + read_mode_group = NULL; + mask = NULL; if (command == K_GOTO_GROUP) *************** *** 659,664 **** --- 678,687 ---- } if (gh != orig_group) { + if (gh == read_mode_group) { + o_cur_first = gh->current_first; + gh->current_first = 0; + } if (gh->current_first > 0) { msg("Group %s already active", gh->group_name); goto_return(ME_NO_REDRAW); *************** *** 667,676 **** } ans1 = ah ? 's' : 'a'; if (gh != orig_group) { if (gh->unread_count > 0) ans1 = 'j'; } else { ! if (gh->unread_count > 0 && gh->current_first > (gh->first_article + 1)) ans1 = 'u'; else if (gh->current_first <= gh->first_db_article) ans1 = 's'; /* no more articles to read */ --- 690,702 ---- } ans1 = ah ? 's' : 'a'; + if (gh == read_mode_group) { + ans1 = 's'; + } else if (gh != orig_group) { if (gh->unread_count > 0) ans1 = 'j'; } else { ! if (gh->unread_count > 0 && gh->current_first > entry_first_article) ans1 = 'u'; else if (gh->current_first <= gh->first_db_article) ans1 = 's'; /* no more articles to read */ *************** *** 746,757 **** if (gh != orig_group) goto enter_new_level; ! if (gh->current_first <= gh->first_db_article) { msg("No extra articles"); goto_return(ME_NO_REDRAW); } ! if (access_group(gh, first, gh->current_first == gh->first_article + 1 ? gh->last_db_article : gh->current_first - 1, ACC_EXTRA_ARTICLES | ACC_ALSO_CROSS_POSTINGS | ACC_ALSO_READ_ARTICLES | ACC_ONLY_READ_ARTICLES, --- 772,785 ---- if (gh != orig_group) goto enter_new_level; ! if (!only_unread_articles && gh->current_first <= gh->first_db_article) { msg("No extra articles"); goto_return(ME_NO_REDRAW); } ! if (first < gh->first_db_article) first = gh->first_db_article; ! ! if (access_group(gh, first, only_unread_articles ? gh->last_db_article : gh->current_first - 1, ACC_EXTRA_ARTICLES | ACC_ALSO_CROSS_POSTINGS | ACC_ALSO_READ_ARTICLES | ACC_ONLY_READ_ARTICLES, *************** *** 760,765 **** --- 788,794 ---- goto_return(ME_NO_REDRAW); } + only_unread_articles = 0; gh->current_first = first; goto_return(ME_REDRAW); *************** *** 819,830 **** enter_new_level: mark_memory(&mem_marker); m_endinput(); menu_cmd = group_menu(gh, first, access_mode, mask, menu); release_memory(&mem_marker); goto_exit: if (gh != orig_group) { - if (gh != NULL) gh->current_first = 0; if (orig_group) init_group(orig_group); } --- 848,864 ---- enter_new_level: mark_memory(&mem_marker); m_endinput(); + if (o_cur_first < 0) o_cur_first = gh->current_first; menu_cmd = group_menu(gh, first, access_mode, mask, menu); release_memory(&mem_marker); goto_exit: + if (gh && o_cur_first >= 0) gh->current_first = o_cur_first; + + if (read_mode_group) + orig_group = read_mode_group; + if (gh != orig_group) { if (orig_group) init_group(orig_group); } *** ./LAST/inews/conf.h Mon Jun 25 15:46:42 1990 --- inews/conf.h Fri Jul 27 20:24:51 1990 *************** *** 36,42 **** #endif /* ! * Define your local domain name. You *must* define something here. * * You are not strictly *required* to have a domain name; nonetheless * it's a good idea. If you are on the Internet or otherwise have a --- 36,44 ---- #endif /* ! * Define your local domain name. You *must* define something, either ! * here, in config.h, or elsewhere according to your local standards. ! * See comment below on HIDDENNET. * * You are not strictly *required* to have a domain name; nonetheless * it's a good idea. If you are on the Internet or otherwise have a *************** *** 44,53 **** * a uucp-only site, use ".uucp" for now and go get a real name. * * Note that if you imbed your domain name in the hostname and you don't ! * use HIDDENNET, you should comment out the definition. */ ! #define DOMAIN "iti.org" /* * If you define this, the hostname will not appear in the posting --- 46,57 ---- * a uucp-only site, use ".uucp" for now and go get a real name. * * Note that if you imbed your domain name in the hostname and you don't ! * use HIDDENNET, you may get a period on the end of your fully qualified ! * domian name (FQDN) in postings. In that case, use HIDDENNET and ! * define DOMAIN to be your FQDN. */ ! /* #define DOMAIN "frobozz.com.bogus" */ /* * If you define this, the hostname will not appear in the posting *** ./LAST/inst.sh Mon Jul 16 17:38:44 1990 --- inst.sh Wed Aug 22 12:27:24 1990 *************** *** 326,331 **** --- 326,332 ---- echo echo Installing manuals + PL="`echo $VERSION | sed -e 's/ .*$//'`" { echo $UMAN_DIR $UMAN_SECT .1 echo $SMAN_DIR $SMAN_SECT .1m *************** *** 339,345 **** do MAN=`basename ${i} $SRC` NEW=$DIR/${MAN}.$SECT ! cp $i $NEW ./inst chmod 644 $NEW echo $MAN in $NEW done --- 340,346 ---- do MAN=`basename ${i} $SRC` NEW=$DIR/${MAN}.$SECT ! sed -e '/^\.TH /s/6.4/'${PL}'/' $i > $NEW ./inst chmod 644 $NEW echo $MAN in $NEW done *** ./LAST/kill.c Thu Jul 19 18:12:15 1990 --- kill.c Mon Sep 17 13:51:01 1990 *************** *** 139,145 **** if (do_select && (flag & AUTO_SELECT) == 0) goto failed; if (do_kill && (flag & AUTO_KILL) == 0) goto failed; ! if (kill_debug) print_kill(kl); if (flag & KILL_UNLESS_MATCH) *unlessp = 1; --- 139,145 ---- if (do_select && (flag & AUTO_SELECT) == 0) goto failed; if (do_kill && (flag & AUTO_KILL) == 0) goto failed; ! if (kill_debug && print_kill(kl) < 0) kill_debug = 0; if (flag & KILL_UNLESS_MATCH) *unlessp = 1; *************** *** 225,235 **** if (unless_match) goto did_kill; no_kill: ! if (kill_debug) pg_end(); return 0; did_kill: ! if (kill_debug) pg_end(); killed_articles++; return 1; } --- 225,235 ---- if (unless_match) goto did_kill; no_kill: ! if (kill_debug && pg_end() < 0) kill_debug = 0; return 0; did_kill: ! if (kill_debug && pg_end() < 0) kill_debug = 0; killed_articles++; return 1; } *************** *** 327,333 **** } else re = NULL; ! killf = open_file(relative(nn_directory, "kill"), OPEN_APPEND); if (killf == NULL) { msg("cannot create kill file"); return; --- 327,333 ---- } else re = NULL; ! killf = open_file(relative(nn_directory, KILL_FILE), OPEN_APPEND); if (killf == NULL) { msg("cannot create kill file"); return; *************** *** 608,617 **** if (fwrite(cp, sizeof(char), len, patternf) != len) goto err3; flag |= GROUP_REGEXP | GROUP_REGEXP_HDR ; - header.ckh_regexp_size++; } else { ! if ((gh = lookup(cp)) == NULL) { ! printf("Unknown group in kill file: %s\n", cp); any_errors++; goto drop_entry; } --- 608,616 ---- if (fwrite(cp, sizeof(char), len, patternf) != len) goto err3; flag |= GROUP_REGEXP | GROUP_REGEXP_HDR ; } else { ! if ((gh = lookup(cp)) == NULL || (gh->master_flag & M_IGNORE_GROUP)) { ! printf("Unknown/ignored group in kill file: %s\n", cp); any_errors++; goto drop_entry; } *************** *** 692,697 **** --- 691,697 ---- goto err3; header.ckh_entries++; + if (flag & GROUP_REGEXP) header.ckh_regexp_size++; } } *************** *** 838,844 **** tb++; } else if (entry.ck_group >= 0) { ! gh = active_groups + entry.ck_group; kl->next_kill = (kill_list_entry *)(gh->kill_list); gh->kill_list = (char *)kl; } else { --- 838,844 ---- tb++; } else if (entry.ck_group >= 0) { ! gh = ACTIVE_GROUP(entry.ck_group); kl->next_kill = (kill_list_entry *)(gh->kill_list); gh->kill_list = (char *)kl; } else { *** ./LAST/man/nn.1.A Tue Jun 12 11:46:44 1990 --- man/nn.1.A Tue Sep 18 12:24:48 1990 *************** *** 1106,1111 **** --- 1106,1113 ---- .I body of the article will be escaped by a tilde (e.g. ~From: ...) to enable \fInn\fP to split the folder into separate articles. + The escape string can be redefined via the + \fBembedded-header-escape\fP variable. .LP Articles can optionally be saved in MAIL or MMDF compatible format by setting the \fBmail-format\fP and \fBmmdf-format\fP variables. *** ./LAST/man/nn.1.B Mon Jul 16 17:38:46 1990 --- man/nn.1.B Tue Sep 18 12:24:48 1990 *************** *** 814,820 **** Has no effect besides redrawing the screen if necessary. If an extended command (one which is prefixed by a :) produces any output requirering the screen to be redrawn, the screen will not be redrawn ! immediately if the variable \fBdelayed-redraw\fP is set (useful on slow terminals). Instead another \fB:\fP prompt is shown to allow you to enter a new extended command immediately. It is sufficient to hit .B return --- 814,820 ---- Has no effect besides redrawing the screen if necessary. If an extended command (one which is prefixed by a :) produces any output requirering the screen to be redrawn, the screen will not be redrawn ! immediately if the variable \fBdelay-redraw\fP is set (useful on slow terminals). Instead another \fB:\fP prompt is shown to allow you to enter a new extended command immediately. It is sufficient to hit .B return *************** *** 898,903 **** \fIread\fP! .LP \fBRelated variables\fP: ! backup, bug-report-address, delayed-redraw, keep-unsubscribed, unsubscribe-mark-read, mail, pager, sort-mode. .\" ENDPART B --- 898,903 ---- \fIread\fP! .LP \fBRelated variables\fP: ! backup, bug-report-address, delay-redraw, keep-unsubscribed, unsubscribe-mark-read, mail, pager, sort-mode. .\" ENDPART B *** ./LAST/man/nn.1.C Thu Jul 19 18:12:17 1990 --- man/nn.1.C Tue Sep 18 12:24:48 1990 *************** *** 171,176 **** --- 171,183 ---- .LP The following variables are available: .TP + \fBalso-full-digest\fP (boolean, default false) + When a digest is split, the digest itself is not normally included on + the menu, and as such the initial adminstrative information is not + available. Setting \fBalso-full-digest\fP will cause the (unsplit) + digest to be included on the menu. These articles are marked with a @ + at the beginning of the subject. + .TP \fBalso-subgroups\fP (boolean, default true) When set, a group name in the presentation sequence will also cause all the subgroups of the group to be included, for example, comp.unix *************** *** 427,432 **** --- 434,444 ---- \fBeditor\fP \fIcommand\fP (string, default not set) When set, it will override the current EDITOR environment variable when editing responses and new articles. + .TP + \fBembedded-header-escape\fP \fIstring\fP (string, default '~') + When saving an article to a file, header lines embedded in the body of + the article are escaped using this string to make it possible for + \fInn\fP to split the folder correctly afterwards. .TP \fBentry-report-limit\fP \fIarticles\fP (integer, default 300) Normally, \fInn\fP will just move the cursor to the upper left corner *** ./LAST/master.c Thu Jul 19 18:12:18 1990 --- master.c Fri Aug 31 14:11:01 1990 *************** *** 272,278 **** --- 272,283 ---- master.free_groups--; + #ifdef MALLOC_64K_LIMITATION + gh = newobj(group_header, 1); + active_groups[master.number_of_groups] = gh; + #else gh = &active_groups[master.number_of_groups]; + #endif gh->group_name_length = strlen(name); gh->group_name = copy_str(name); *************** *** 803,809 **** arg = atol(bp); if (arg >= master.number_of_groups) continue; ! gh = (arg >= 0) ? &active_groups[arg] : NULL; if ((bp = strchr(bp, ';')) == NULL) continue; bp++; --- 808,814 ---- arg = atol(bp); if (arg >= master.number_of_groups) continue; ! gh = (arg >= 0) ? ACTIVE_GROUP(arg) : NULL; if ((bp = strchr(bp, ';')) == NULL) continue; bp++; *** ./LAST/more.c Thu Jul 19 18:12:19 1990 --- more.c Thu Aug 23 19:02:39 1990 *************** *** 36,41 **** --- 36,42 ---- import int flush_typeahead; import int case_fold_search; import int echo_prefix_key; + import int re_layout; import char delayed_msg[]; *************** *** 282,287 **** --- 283,304 ---- return buf; } + static brief_header_line(ah, lno) + register article_header *ah; + int lno; + { + int o_re_layout; + + so_gotoxy(0, lno, 0); + so_printf("%s: ", ah->sender); + o_re_layout = re_layout; + if (re_layout_more >= 0) re_layout = re_layout_more; + prt_replies(ah->replies); + re_layout = o_re_layout; + so_printf("%s", ah->subject); + so_end(); + } + more(ah, mode, screen_offset) article_header *ah; int mode, screen_offset; *************** *** 357,377 **** if (preview_window < 1 && Lines - screen_offset < min_pv_window) screen_offset = 0; else { ! #ifdef notdef ! so_printxy(0, screen_offset++, "%s: %s ", ah->sender, ah->subject); ! #else ! import int re_layout; ! int o_re_layout; ! ! so_gotoxy(0, screen_offset++, 0); ! so_printf("%s: ", ah->sender); ! o_re_layout = re_layout; ! if (re_layout_more >= 0) re_layout = re_layout_more; ! prt_replies(ah->replies); ! re_layout = o_re_layout; ! so_printf("%s", ah->subject); ! so_end(); ! #endif if (!STANDOUT) screen_offset++; clrline(); } --- 374,380 ---- if (preview_window < 1 && Lines - screen_offset < min_pv_window) screen_offset = 0; else { ! brief_header_line(ah, screen_offset++); if (!STANDOUT) screen_offset++; clrline(); } *************** *** 513,521 **** if (screen_offset == 0 && linenum == 1) { if (show_article_date) so_printxy(-1, 0, send_date); ! /* so_printxy will cut subject */ ! so_printxy(0, lno, "%s: %s ", ah->sender, ah->subject); ! lno++; if (!STANDOUT) lno++; } } --- 516,522 ---- if (screen_offset == 0 && linenum == 1) { if (show_article_date) so_printxy(-1, 0, send_date); ! brief_header_line(ah, lno++); if (!STANDOUT) lno++; } } *************** *** 641,647 **** --- 642,652 ---- lno1 = lno; } } else + { + if (match_expr && linenum == match_botline) + msg("Searching..."); linenum++; + } lp = linebuf; col = 0; *************** *** 1301,1306 **** --- 1306,1312 ---- if (regular_expr) freeobj(regular_expr); if (case_fold_search) fold_string(fname); regular_expr = regcomp(fname); + match_lines = 0; } case K_NEXT_MATCH: *** ./LAST/newsrc.c Thu Jul 19 18:12:20 1990 --- newsrc.c Mon Sep 3 17:44:39 1990 *************** *** 10,18 **** --- 10,24 ---- #include "term.h" #include "articles.h" + #ifdef sel + /* Remove Gould SELbus software name collision */ + #undef sel + #endif + #define TR(arg) printf arg import char *news_lib_directory, *db_directory; + import char *home_directory; import char *pname; import int verbose; *************** *** 177,183 **** #define MAX_RNLAST_LINE 6 static char *rnlast_line[MAX_RNLAST_LINE]; ! static char *rnlast_path; static time_t get_last_new() { --- 183,189 ---- #define MAX_RNLAST_LINE 6 static char *rnlast_line[MAX_RNLAST_LINE]; ! #define rnlast_path relative(home_directory, ".rnlast") static time_t get_last_new() { *************** *** 187,193 **** time_t t; if (new_group_action == RCX_RNLAST) { - rnlast_path = home_relative(".rnlast"); lf = open_file(rnlast_path, OPEN_READ); if (lf == NULL) goto no_file; --- 193,198 ---- *************** *** 243,249 **** else /* can't be perfect -- don't update */ fputs(rnlast_line[RN_ACTIVE_TIMES_OFFSET], lf); for (i = 0; i < MAX_RNLAST_LINE; i++) freeobj(rnlast_line[i]); - freeobj(rnlast_path); } else { lf = open_file(relative(nn_directory, "LAST"), OPEN_CREATE|MUST_EXIST); fprintf(lf, "%ld\n%s\n", (long)lastg->creation_time, lastg->group_name); --- 248,253 ---- *** ./LAST/nn.c Thu Jul 19 18:12:21 1990 --- nn.c Wed Aug 22 13:45:32 1990 *************** *** 32,37 **** --- 32,38 ---- export int article_limit = -1, also_read_articles = 0, + also_full_digest = 0, batch_mode = 0, conf_auto_quit = 0, do_kill_handling = 1, *************** *** 141,146 **** --- 142,149 ---- access_mode |= ACC_ALSO_READ_ARTICLES; if (dont_split_digests) access_mode |= ACC_DONT_SPLIT_DIGESTS; + if (also_full_digest) + access_mode |= ACC_ALSO_FULL_DIGEST; if (dont_sort_articles) access_mode |= ACC_DONT_SORT_ARTICLES; *************** *** 559,564 **** --- 562,568 ---- if (last_motd >= cur_motd) return 0; + unlink(dot_motd); fclose(open_file(dot_motd, OPEN_CREATE|MUST_EXIST)); clrdisp(); *** ./LAST/nnusage.sh Wed Apr 25 19:15:54 1990 --- nnusage.sh Tue Sep 4 16:17:55 1990 *************** *** 13,24 **** shift ;; -t) SORTMODE="+1nr" shift ;; *) LOOP=false esac done if [ -f $DB/acct -a -f $BIN/nnacct ] ; then ! $BIN/nnacct -r $OPT $@ | sort $SORTMODE exit fi --- 13,33 ---- shift ;; -t) SORTMODE="+1nr" shift ;; + -at) OPT="$OPT -a" + ALL=true + SORTMODE="+1nr" + shift ;; + -*) echo "$0: unknown option: $1" + exit 1 + ;; *) LOOP=false + ;; esac done if [ -f $DB/acct -a -f $BIN/nnacct ] ; then ! echo "USER USAGE QUOTA LAST_ACTIVE COST/PERIOD" ! $BIN/nnacct -r $OPT $@ | sed -e 1d | sort $SORTMODE exit fi *** ./LAST/pack_name.c Tue May 22 12:53:56 1990 --- pack_name.c Tue Sep 4 18:39:44 1990 *************** *** 179,184 **** --- 179,185 ---- int lname, lfirst, lmiddle, llast, sep, i; int drop_space, prev_space; char *separator[SEP_MAXIMUM]; + int ignore_braces = 0; dest[0] = NUL; *************** *** 185,190 **** --- 186,192 ---- if (source == NULL || source[0] == NUL) return 0; + full_scan: p = source, q = namebuf, n = 0; maxq = namebuf + sizeof namebuf - 1; *************** *** 197,220 **** if (q == namebuf) continue; break; } if (IGNORE(c)) continue; if (q == namebuf && IS_SPACE(c)) continue; if (c == '(') { ! if (*p == ')') { ! p++; ! continue; ! } ! if (n++ == 0) { q = namebuf; goto new_partition; } continue; } ! if (c == ')') { ! if (--n == 0) break; ! continue; ! } ! if (n > 1) continue; if (q >= maxq) break; *q++ = c; if (IS_SEPARATOR(c)) { --- 199,219 ---- if (q == namebuf) continue; break; } + if (c == ')') { + if (--n == 0 && !ignore_braces) break; + continue; + } if (IGNORE(c)) continue; if (q == namebuf && IS_SPACE(c)) continue; if (c == '(') { ! if (n++ == 0 && !ignore_braces) { q = namebuf; goto new_partition; } continue; } ! if (n > 0) ! if (ignore_braces || n > 1) continue; if (q >= maxq) break; *q++ = c; if (IS_SEPARATOR(c)) { *************** *** 239,244 **** --- 238,248 ---- } *q = NUL; + + if (namebuf[0] == NUL && !ignore_braces ) { + ignore_braces = 1; + goto full_scan; + } if (namebuf[0] == NUL) return 0; *** ./LAST/patchlevel.h Thu Jul 19 18:12:22 1990 --- patchlevel.h Tue Sep 18 12:24:06 1990 *************** *** 20,26 **** * 1990-07-09: Patch #7 (6.4.7) - LOW * 1990-07-16: Patch #8 (6.4.8) - HIGH * 1990-07-19: Patch #9 (6.4.9) - MEDIUM */ ! #define PATCHLEVEL 9 --- 20,27 ---- * 1990-07-09: Patch #7 (6.4.7) - LOW * 1990-07-16: Patch #8 (6.4.8) - HIGH * 1990-07-19: Patch #9 (6.4.9) - MEDIUM + * 1990-09-18: Patch #10 (6.4.10) - HIGH */ ! #define PATCHLEVEL 10 *** ./LAST/prefix.c Mon Jul 16 17:38:53 1990 --- prefix.c Wed Aug 22 17:12:23 1990 *************** *** 28,34 **** #ifdef AVOID_SHELL_EXEC fprintf(f, ":\n"); #else ! fprintf(f, "#!/bin/sh\n"); #endif fprintf(f, "\n# Generated by nn release %s at %s\n\n", version_id, date_time((time_t)0)); --- 28,34 ---- #ifdef AVOID_SHELL_EXEC fprintf(f, ":\n"); #else ! fprintf(f, "#!%s\n", SHELL); #endif fprintf(f, "\n# Generated by nn release %s at %s\n\n", version_id, date_time((time_t)0)); *** ./LAST/save.c Mon Jul 16 17:38:53 1990 --- save.c Tue Sep 11 17:53:17 1990 *************** *** 23,28 **** --- 23,30 ---- export int conf_append = 0; export int conf_create = 1; + export char *saved_header_escape = "~"; + export char *print_header_lines = "FDGS"; export char *save_header_lines = "FDNS"; static char *short_header_lines; *************** *** 523,530 **** while (ftell(art) < ah->lpos && fgets(copybuf, 512, art)) { lcount++; if (rot13_active) rot13_line(copybuf); ! if (with_header && is_header_line(copybuf)) ! fputc('~', save_file); fputs(copybuf, save_file); if (s_pipe) goto broken_pipe; } --- 525,532 ---- while (ftell(art) < ah->lpos && fgets(copybuf, 512, art)) { lcount++; if (rot13_active) rot13_line(copybuf); ! if (saved_header_escape && with_header && is_header_line(copybuf)) ! fputs(saved_header_escape, save_file); fputs(copybuf, save_file); if (s_pipe) goto broken_pipe; } *** ./LAST/sequence.c Thu Jul 19 18:12:22 1990 --- sequence.c Fri Aug 31 14:11:00 1990 *************** *** 445,451 **** if (hex_group_args) { sscanf(group, "%x", &gnum); if (gnum < 0 || gnum >= master.number_of_groups) continue; ! gh = &active_groups[gnum]; if (enter_sequence(SHOW_NORMAL, gh)) any++; continue; } --- 445,451 ---- if (hex_group_args) { sscanf(group, "%x", &gnum); if (gnum < 0 || gnum >= master.number_of_groups) continue; ! gh = ACTIVE_GROUP(gnum); if (enter_sequence(SHOW_NORMAL, gh)) any++; continue; } *** ./LAST/sort.c Mon Apr 23 18:37:14 1990 --- sort.c Tue Sep 4 16:48:57 1990 *************** *** 98,104 **** if ((**ah1).t_stamp > (**ah2).t_stamp) return 1; if ((**ah1).t_stamp < (**ah2).t_stamp) return -1; ! return 0; } /* data_subj_date can only be used after root_t_stamp is set */ --- 98,104 ---- if ((**ah1).t_stamp > (**ah2).t_stamp) return 1; if ((**ah1).t_stamp < (**ah2).t_stamp) return -1; ! return order_arrival(ah1, ah2); } /* data_subj_date can only be used after root_t_stamp is set */ *************** *** 131,137 **** { if ((**ah1).t_stamp > (**ah2).t_stamp) return 1; if ((**ah1).t_stamp < (**ah2).t_stamp) return -1; ! return 0; } static order_from_date(ah1, ah2) --- 131,137 ---- { if ((**ah1).t_stamp > (**ah2).t_stamp) return 1; if ((**ah1).t_stamp < (**ah2).t_stamp) return -1; ! return order_arrival(ah1, ah2); } static order_from_date(ah1, ah2) *** ./LAST/term.c Thu Jul 19 18:12:23 1990 --- term.c Fri Sep 7 19:49:25 1990 *************** *** 84,89 **** --- 84,90 ---- static char keypad_local[64], keypad_xmit[64]; int magic_cookie_glitch; /* magic cookie size */ + int ceol_standout_glitch; /* hp brain damage! */ #define putp(str) tputs(str, 0, outc) *************** *** 308,313 **** --- 309,323 ---- terminal_speed = 30; } + static raw_not_ok_error() + { + if (batch_mode) return 0; + user_error("Not prepared for terminal i/o"); + } + + #define RAW_CHECK if (terminal_speed == 0) return raw_not_ok_error() + #define BATCH_CHECK if (terminal_speed == 0) return 0 + init_term(full) int full; { *************** *** 319,324 **** --- 329,336 ---- term_name = "batch"; close(0); open("/dev/null", 0); + STANDOUT = 0; + cookie_size = 1; return; } *************** *** 380,385 **** --- 392,398 ---- cookie_size = tgetnum("sg"); WRAP = tgetflag("am"); + ceol_standout_glitch = tgetflag("xs"); opt_cap("ti", enter_ca_mode); opt_cap("te", exit_ca_mode); *************** *** 478,483 **** --- 491,498 ---- home() { + BATCH_CHECK; + putp(cursor_home); } *************** *** 497,502 **** --- 512,519 ---- gotoxy(c, l) int c, l; { + BATCH_CHECK; + curxy_c = c; curxy_l = l; putp(tgoto(cursor_address, c, l)); } *************** *** 503,508 **** --- 520,527 ---- clrdisp() { + BATCH_CHECK; + #ifdef USE_TERMINFO putp(clear_screen); /* tputs is broken on UNISYS I've been told */ #else *************** *** 514,519 **** --- 533,540 ---- clrline() { + BATCH_CHECK; + putp(clr_eol); fl; } *************** *** 523,528 **** --- 544,551 ---- { register int olineno= lineno; + BATCH_CHECK; + if (HAS_CAP(clr_eos)) { #ifdef USE_TERMINFO putp(clr_eos); *************** *** 581,586 **** --- 604,610 ---- fmt = va_arg1(char *); if (!so_active) { + if (ceol_standout_glitch) highlight(0); vprintf(fmt, va_args2toN); return; } *************** *** 619,625 **** if ((so_b & 1) && (!STANDOUT || !cookie_size)) putchar(SP); ! if (STANDOUT) putp(enter_standout_mode); fputs(so_buf, stdout); --- 643,652 ---- if ((so_b & 1) && (!STANDOUT || !cookie_size)) putchar(SP); ! if (STANDOUT) { ! if (ceol_standout_glitch) clrline(); ! putp(enter_standout_mode); ! } fputs(so_buf, stdout); *************** *** 679,684 **** --- 706,713 ---- visual_on() { + BATCH_CHECK; + if (HAS_CAP(enter_ca_mode)) { putp(enter_ca_mode); is_visual = 1; *************** *** 711,716 **** --- 740,747 ---- #ifdef CBREAK raw() { + RAW_CHECK; + if (is_raw == 1) return; is_raw = 1; *************** *** 726,731 **** --- 757,763 ---- { if (is_raw == 0) return 0; + RAW_CHECK; RAW_MODE_OFF; is_raw = 0; return 1; *************** *** 736,741 **** --- 768,775 ---- raw() { + RAW_CHECK; + if (!flow_control) { if (!must_set_raw) return; must_set_raw = 0; *************** *** 754,759 **** --- 788,795 ---- if (!is_raw) return 0; + RAW_CHECK; + RAW_MODE_OFF; is_raw = 0; *************** *** 766,771 **** --- 802,808 ---- int was_raw = is_raw; if (is_raw) { + RAW_CHECK; RAW_MODE_OFF; is_raw = 0; } *************** *** 781,786 **** --- 818,825 ---- flush_input() { + BATCH_CHECK; + #ifdef HAVE_TERMIO ioctl(0, TCFLSH, 0); do_flush_input = 1; *************** *** 1316,1321 **** --- 1355,1362 ---- ding() { + BATCH_CHECK; + putp(bell_str); fl; } *************** *** 1512,1517 **** --- 1553,1560 ---- msg_ptr = msg_stack; } + BATCH_CHECK; + gotoxy(0, Lines-1); fputs(errmsg, stdout); clrline(); *************** *** 1524,1529 **** --- 1567,1574 ---- clrmsg(col) int col; { + BATCH_CHECK; + gotoxy(0, prompt_line + 1); clrpage(prompt_line + 1); if (col >= 0) *************** *** 1544,1549 **** --- 1589,1596 ---- static char saved_p[FILENAME]; use_vararg; + BATCH_CHECK; + start_vararg; fmt = va_arg1(char *); *************** *** 1639,1644 **** --- 1686,1693 ---- { int was_raw, c, dmp; + BATCH_CHECK; + was_raw = is_raw; if (!is_raw) raw(); if (line == 0) *************** *** 1702,1707 **** --- 1751,1761 ---- { int c; + if (batch_mode) { + putchar(NL); + return 0; + } + pg_line++; if (pg_line < Lines) { gotoxy(pg_col, pg_line); *************** *** 1740,1757 **** pg_indent(pos) int pos; { gotoxy(pg_col + pos, pg_line); } pg_end() { if (pg_quit == 0 && pg_next() == 0) ! any_key(0); if (pg_regexp) { freeobj(pg_regexp); pg_regexp = NULL; } } --- 1794,1819 ---- pg_indent(pos) int pos; { + BATCH_CHECK; + gotoxy(pg_col + pos, pg_line); } pg_end() { + int c; + if (pg_quit == 0 && pg_next() == 0) ! c = any_key(0); ! else ! c = K_interrupt; if (pg_regexp) { freeobj(pg_regexp); pg_regexp = NULL; } + + return c == K_interrupt ? -1 : 0; } *************** *** 1758,1763 **** --- 1820,1827 ---- user_delay(ticks) int ticks; { + BATCH_CHECK; + if (ticks <= 0 || conf_dont_sleep) { printf(" <>"); any_key(10000); *** ./LAST/variable.c Thu Jul 19 18:12:24 1990 --- variable.c Mon Sep 17 15:30:45 1990 *************** *** 16,21 **** --- 16,23 ---- *decode_header_file, *default_distribution, *default_save_file, + *distribution_follow, + *distribution_post, *editor_program, *extra_mail_headers, *extra_news_headers, *************** *** 39,44 **** --- 41,47 ---- *response_dflt_answer, *save_counter_format, *save_header_lines, + *saved_header_escape, *shade_on_attr, *shade_off_attr, *spell_checker, *************** *** 49,54 **** --- 52,58 ---- import int /* boolean variables */ also_cross_postings, + also_full_digest, also_subgroups, append_sig_mail, append_sig_post, *************** *** 218,223 **** --- 222,228 ---- int var_flags; char **var_addr; } variables[] = { + "also-full-digest", BOOL 0, (char **)&also_full_digest, "also-subgroups", BOOL INIT 0, (char **)&also_subgroups, "append-signature-mail", BOOL 0, (char **)&append_sig_mail, "append-signature-post", BOOL 0, (char **)&append_sig_post, *************** *** 259,264 **** --- 264,270 ---- "edit-response-check", BOOL 0, (char **)&empty_answer_check, "edit-unshar-command", BOOL 0, (char **)&edit_unshar_command, "editor", STR 0, (char **)&editor_program, + "embedded-header-escape", STR 0, (char **)&saved_header_escape, "entry-report-limit", INT 0, (char **)&entry_message_limit, "erase-key", KEY 0, (char **)&erase_key, "expert", BOOL 4, (char **)&novice, *************** *** 267,272 **** --- 273,279 ---- "flush-typeahead", BOOL 0, (char **)&flush_typeahead, "folder", STR 2, (char **)&folder_directory, "folder-save-file", STR 3, (char **)&folder_save_file, + "follow-distribution", STR 0, (char **)&distribution_follow, "fsort", BOOL 2, (char **)&dont_sort_folders, "header-lines", STR 0, (char **)&header_lines, "help-key", KEY 0, (char **)&help_key, *************** *** 320,325 **** --- 327,333 ---- "overlap", INT 0, (char **)&overlap, "pager", STR SAFE 3, (char **)&pager, "patch-command", STR SAFE 1, (char **)patch_command, + "post-distribution", STR 0, (char **)&distribution_post, "preview-continuation", INT 0, (char **)&preview_continuation, "preview-mark-read", BOOL 0, (char **)&preview_mark_read, "previous-also-read", BOOL 0, (char **)&prev_also_read, *************** *** 534,540 **** case V_BOOLEAN: ! if (val_string) if (val_string[0] == 'o') on = val_string[1] == 'n'; /* on */ else --- 542,549 ---- case V_BOOLEAN: ! adjust(val_string); ! if (val_string && *val_string != NUL) if (val_string[0] == 'o') on = val_string[1] == 'n'; /* on */ else *************** *** 1056,1060 **** --- 1065,1114 ---- if (!all && (var->var_flags & V_MODIFIED) == 0) continue; str = var_value(var, tag); fprintf(f, "%s%s='%s'\n", all ? tag : "", var->var_name, str); + } + } + + /* + * var_options(string_var *, options, result *) + * + * test whether "string_var" contains any of the options + * listed in "options" (NUL-separated list of names ended with + * double NUL). On return, string_var is advanced over all + * recognized options and the result will have the bits corresponding + * to the recognized options set. + */ + + var_options(str, options, res) + char **str; + register char *options; + flag_type *res; + { + char word[128]; + char *optab[32]; + register char **op, *wp, c; + register int n; + + for (op = optab; *options != NUL; op++, options++) { + *op = options; + while (*options) options++; + } + *op = NULL; + + *res = 0; + + options = *str; + while (*options) { + for (wp = word; (c = *options) != NUL; *wp++ = c, options++) + if (isascii(c) && isspace(c)) break; + while ((c = *options) && isascii(c) && isspace(c)) options++; + *wp = NUL; + + for (op = optab, n = 0; *op != NULL; op++, n++) { + if (strcmp(word, *op)) continue; + *res |= FLAG(n); + *str = options; + break; + } + if (*op == NULL) break; } }