This is an official patch to nn release 6.4 ------------------------------------------- PATCH #11 Priority: HIGH This patch fixes a syntax error introduced in patch #10 which causes term.c not to compile on some systems. It also fixes a nasty bug in the article header sorting which could provoke a crash in qsort; unfortunately the fix involves changing the interpretation of the subject-match-limit variable: =================================================================== The subject-match-limit variable is now a simple compare only first "length" characters limit whereas before it was only used if one subject was a true suffix of another subject. Unfortunately, the old interpretation made the sorting non-deterministic and it could cause qsort() to crash. The default value is now changed to 256 effectively disabling the match-limit unless explicitly set to a lower limit. Thanks to Paul Eggert for a detailed analysis on this problem. =================================================================== This patch also changes the splitting of folders in a way which is not backwards compatible: When splitting a folder (e.g. G +folder), nn will now determine the format of the folder (mail, mmdf, standard) from the *first* article in the folder, and the rest of the folder is split according to this format. (Thanks to Bernd Wechner for a lot of patches to the folder and digest code). This may cause problems with current folders which are a mixture of different formats; such folders must be manually reformatted to use only a single format. To ensure that folders are used properly, the save-full and save-short commands will now append articles to an existing folder using the current format of the folder (determined from the first article). Consequently, the mmdf-format and mail-format variables are now only used to determine the type to use for new folders. =================================================================== Notice: Updates to the manual for the new features are postponed to the next patch to keep this patch at a reasonable size. 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/admin.c Tue Sep 18 12:44:49 1990 --- admin.c Wed Sep 19 18:40:59 1990 *************** *** 781,787 **** char command[FILENAME*2]; char *rmprog; ! if (!file_exist(news_active, "w")) { printf("Not privileged to run rmgroup\n"); return; } --- 781,787 ---- char command[FILENAME*2]; char *rmprog; ! if (user_id != 0 && !file_exist(news_active, "w")) { printf("Not privileged to run rmgroup\n"); return; } *** ./LAST/aux.sh Mon Jul 9 17:59:52 1990 --- aux.sh Tue Sep 25 16:08:24 1990 *************** *** 334,343 **** follow|post) { if ${POST_PIPE} ; then ! $POST < $FINAL x=$? else ! $POST $FINAL x=$? fi case $x in --- 334,343 ---- follow|post) { if ${POST_PIPE} ; then ! $POST < $FINAL 2>&1 x=$? else ! $POST $FINAL 2>&1 x=$? fi case $x in *************** *** 344,350 **** 0) sleep 60 ;; *) echo $INEWS failed ;; esac ! } | fgrep -v "mailing your article to" ;; *) --- 344,355 ---- 0) sleep 60 ;; *) echo $INEWS failed ;; esac ! } | sed \ ! -e "/spooled for later processing/d" \ ! -e "/problem has been taken care of/d" \ ! -e "/mailing your article to/d" \ ! -e "/being mailed to/d" \ ! -e "/is moderated/d" ;; *) *** ./LAST/conf/m-symmetry.h Sat Mar 31 23:12:50 1990 --- conf/m-symmetry.h Thu Aug 23 11:41:47 1990 *************** *** 20,25 **** --- 20,28 ---- #define NO_VARARGS #define STRCSPN + /* enable parallel make hook in xmakefile */ + #define PARALLEL_MAKE + /* * Not in network byte order on the 386 */ *** ./LAST/conf/s-pyramid.h Sat Mar 31 23:13:02 1990 --- conf/s-pyramid.h Mon Sep 24 13:14:00 1990 *************** *** 9,13 **** --- 9,17 ---- extern FILE *popen(); + /* The sysV shell has test built-in */ + #undef SHELL + #define SHELL "/.attbin/sh" + #undef MAILX #define MAILX "/usr/.ucbucb/Mail" /* BSD */ *** ./LAST/db.c Tue Sep 18 12:44:53 1990 --- db.c Thu Sep 20 18:01:05 1990 *************** *** 22,27 **** --- 22,29 ---- export int reread_groups_file = 0; /* nnmaster -G */ + export int check_group_access = 0; + export data_header db_hdr; export data_dynamic_data db_data; *************** *** 97,102 **** --- 99,109 ---- /* client */ if (gh->master_flag & M_NO_DIRECTORY) return 0; + + if (check_group_access && !use_nntp) { + *p = NUL; + if (file_exist(group_path_name, "dxr") == 0) return 0; + } *p++ = '/'; *p = NUL; *** ./LAST/digest.c Thu Jul 19 18:12:10 1990 --- digest.c Fri Oct 5 18:12:35 1990 *************** *** 2,7 **** --- 2,11 ---- * (c) Copyright 1990, Kim Fabricius Storm. All rights reserved. * * Digest article handling + * + * The code to do the selective parsing of mail and mmdf formats, + * mail from lines and determining folder types is based on patches + * contributed by Bernd Wechner (bernd@bhpcpd.kembla.oz.au). */ #include "config.h" *************** *** 8,13 **** --- 12,19 ---- #include "news.h" #include "debug.h" + export int strict_from_parse = 2; + #ifdef DG_TEST #define TEST(fmt, x, y) if (Debug & DG_TEST) printf(fmt, x, y) *************** *** 49,59 **** --- 55,196 ---- /* + * is_mail_from_line - Is this a legal unix mail "From " line? + * + * Given a line of input will check to see if it matches the standard + * unix mail "from " header format. Returns 0 if it does and <0 if not. + * + * The check may be very lax or very strict depending upon + * the value of "strict-mail-from-parse": + * + * 0 - Lax, checks only for the string "From ". + * 1 - Strict, checks that the correct number of fields are present. + * 2 - Very strict, also checks that each field contains a legal value. + * + * Assumptions: Not having the definitive unix mailbox reference I have + * assumed that unix mailbox headers follow this format: + * + * From + * + * Where is the address of the sender, being an ordinary + * string with no white space imbedded in it, and is the date of + * posting, in ctime(3C) format. + * + * This would, on the face of it, seem valid. I (Bernd) have yet to find a + * unix mailbox header which doesn't follow this format. + * + * From: Bernd Wechner (bernd@bhpcpd.kembla.oz.au) + * Obfuscated by: KFS (as usual) + */ + + #define MAX_FIELDS 10 + + static char legal_day[] = "SunMonTueWedThuFriSat"; + static char legal_month[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; + static int legal_numbers[] = { 1, 31, 0, 23, 0, 59, 0, 60, 1969, 2199 }; + + int is_mail_from_line(line, namebuf) + char *line; /* Line of text to be checked */ + char *namebuf; /* Optional buffer to place packed sender info */ + { + char *fields[MAX_FIELDS]; + char *sender_tail; + register char *lp, **fp; + register int n, i; + + if (strncmp(line, "From ", 5)) return -100; + if (strict_from_parse == 0) return 0; + + lp = line + 5; + /* sender day mon dd hh:mm:ss year */ + for (n = 0, fp = fields; n < MAX_FIELDS; n++) { + while (*lp && *lp != NL && isascii(*lp) && isspace(*lp)) lp++; + if (*lp == NUL || *lp == NL) break; + *fp++ = lp; + while (*lp && isascii(*lp) && !isspace(*lp)) + if (*lp++ == ':' && (n == 4 || n == 5)) break; + if (n == 0) sender_tail = lp; + } + + if (n < 8) return -200-n; + + fp = fields; + + if (namebuf != NULL) { + char x = *sender_tail; + *sender_tail = NUL; + pack_name(namebuf, *fp, NAME_LENGTH); + *sender_tail = x; + } + + if (strict_from_parse == 1) return 0; + + fp++; + for (i = 0; i < 21; i += 3) + if (strncmp(*fp, &legal_day[i], 3) == 0) break; + if (i == 21) return -1; + + fp++; + for (i = 0; i < 36; i += 3) + if (strncmp(*fp, &legal_month[i], 3) == 0) break; + if (i == 36) return -2; + + for (i = 0; i < 10; i += 2) { + lp = *++fp; + if (!isdigit(*lp)) return -20-i; + n = atoi(lp); + if (n < legal_numbers[i] || legal_numbers[i+1] < n) return -10-i; + } + return 0; + } + + /* * expect that f is positioned at header of an article */ static int is_mmdf_folder = 0; + static int is_mail_folder = 0; + /* + * get_folder_type + * + * Given a file descriptor f, will check what type of folder it is. + * Must be called at zero offset and caller must reposition if necessary. + * Side-effects: sets is_mail_folder, is_mmdf_folder, and current_folder_type. + * Return values: + * -1: folder is empty, + * 0: normal digest, + * 1: UNIX mail format + * 2: MMDF format + */ + + export int current_folder_type; + + int get_folder_type(f) + FILE *f; + { + char line[1024]; + int siz; + + is_mail_folder = 0; + is_mmdf_folder = 0; + + if (fgets(line, 1024, f) == NULL) + return current_folder_type = -1; + + if (strncmp(line, "\001\001\001\001\n", 5) == 0) { + is_mmdf_folder = 1; + return current_folder_type = 2; + } + + if (is_mail_from_line(line, (char *)NULL) == 0) { + is_mail_folder = 1; + return current_folder_type = 1; + } + + return current_folder_type = 0; + } + get_digest_article(f, hdrbuf) FILE *f; news_header_buffer hdrbuf; *************** *** 183,198 **** TEST("\n>>%-.50s ==>>", line, 0); ! if (line[0] == '\001' && strcmp(line, "\001\001\001\001\n") == 0) { digest.dg_lpos = backup_p[backup_index]; - if (!is_mmdf_folder) fseek(f, digest.dg_lpos, 0); --digest.dg_lines; - is_mmdf_folder = 0; return (digest.dg_lines <= 0) ? -1 : 1; } - if (is_mmdf_folder) goto next_line; - for (cp = line; *cp && isascii(*cp) && isspace(*cp); cp++); if (*cp == NUL) { --- 320,335 ---- TEST("\n>>%-.50s ==>>", line, 0); ! if (is_mmdf_folder) { ! /* in an mmdf folder we simply look for the next ^A^A^A^A line */ ! if (line[0] != '\001' || strcmp(line, "\001\001\001\001\n")) ! goto next_line; ! digest.dg_lpos = backup_p[backup_index]; --digest.dg_lines; return (digest.dg_lines <= 0) ? -1 : 1; } for (cp = line; *cp && isascii(*cp) && isspace(*cp); cp++); if (*cp == NUL) { *************** *** 201,206 **** --- 338,353 ---- goto next_line; } + if (is_mail_folder) { + /* in a mail folder we simply look for the next "From " line */ + if (line[0] != 'F' || is_mail_from_line(line, (char *)NULL) < 0) + goto next_line; + + line_type[backup_index] = LN_HEADER; + fseek(f, backup_p[backup_index], 0); + goto found_mail_header; + } + blanks = cp - line; if (*cp == '-') { *************** *** 242,290 **** goto next_line; } ! if (blanks == 0) { ! if (dg_hdr_field(line, 0)) { ! TEST("HEADER", 0, 0); ! line_type[backup_index] = LN_HEADER; ! if (++more_header_lines < MIN_HEADER_LINES) ! goto next_possible_header_line; ! ! /* found block with MIN_HEADER_LINES */ ! ! /* search for beginning of header */ ! TEST("\nSearch for start of header\n", 0, 0); ! for (;;) { ! fseek(f, backup_p[backup_index], 0); ! --digest.dg_lines; ! if (--backup_count == 0) break; ! decrease_index(); ! if ((line_type[backup_index] & (LN_HEADER | LN_TEXT)) == 0) ! break; ! } ! if (digest.dg_lines == 0) { ! TEST("Skipped empty article\n", 0, 0); ! return -1; ! } ! for (;;) { ! digest.dg_lpos = backup_p[backup_index]; ! if (--backup_count < 0) break; ! decrease_index(); ! if ((line_type[backup_index] & (LN_BLANK | LN_DASHED)) == 0) ! break; ! --digest.dg_lines; ! } ! return (digest.dg_lines == 0) ? -1 : 1; ! } ! goto next_possible_header_line; } ! goto next_line; } --- 389,436 ---- goto next_line; } ! if (blanks) ! goto next_line; ! if (!dg_hdr_field(line, 0)) ! goto next_possible_header_line; ! TEST("HEADER", 0, 0); ! line_type[backup_index] = LN_HEADER; ! if (++more_header_lines < MIN_HEADER_LINES) ! goto next_possible_header_line; ! /* found block with MIN_HEADER_LINES */ ! TEST("\nSearch for start of header\n", 0, 0); ! for (;;) { ! fseek(f, backup_p[backup_index], 0); ! --digest.dg_lines; ! if (--backup_count == 0) break; ! decrease_index(); ! if ((line_type[backup_index] & (LN_HEADER | LN_TEXT)) == 0) ! break; ! } ! ! if (digest.dg_lines == 0) { ! TEST("Skipped empty article\n", 0, 0); ! return -1; ! } ! ! found_mail_header: ! ! for (;;) { ! digest.dg_lpos = backup_p[backup_index]; ! if (--backup_count < 0) break; ! decrease_index(); ! if ((line_type[backup_index] & (LN_BLANK | LN_DASHED)) == 0) ! break; ! --digest.dg_lines; } ! return (digest.dg_lines == 0) ? -1 : 1; } *************** *** 307,312 **** --- 453,460 ---- register char *lp; int all; { + static char *dummy; + static char namebuf[NAME_LENGTH+1]; #define check(name, lgt, field) \ if (isascii(lp[lgt]) && isspace(lp[lgt]) && strncmp(name, lp, lgt) == 0) {\ *************** *** 320,331 **** switch (*lp++) { case '\001': ! if (!is_mmdf_folder && strncmp(lp, "\001\001\001\n", 4) == 0) { ! is_mmdf_folder = 1; ! digest.dg_hpos += 5; ! return NULL; ! } ! break; case 'D': case 'd': --- 468,478 ---- switch (*lp++) { case '\001': ! /* In an mmdf folder ^A^A^A^A is skipped at beginning of header */ ! if (!is_mmdf_folder) break; ! if (strncmp(lp, "\001\001\001\n", 4)) break; ! digest.dg_hpos += 5; ! return NULL; case 'D': case 'd': *************** *** 335,341 **** case 'F': case 'f': check("rom:", 4, dg_from); ! break; case 'R': case 'r': --- 482,493 ---- case 'F': case 'f': check("rom:", 4, dg_from); ! if (!is_mail_folder) break; ! if (*--lp != 'F') break; ! if (is_mail_from_line(lp, namebuf) < 0) break; ! /* Store packed sender in dg_from here and return dummy to parser */ ! if (digest.dg_from == NULL) digest.dg_from = namebuf; ! return &dummy; case 'R': case 'r': *** ./LAST/doc/RELEASE_NOTES Tue Sep 18 12:44:55 1990 --- doc/RELEASE_NOTES Thu Oct 4 23:05:05 1990 *************** *** 1163,1168 **** --- 1163,1230 ---- than giving a new level-2 menu - or if it gave a level-2 menu it wasn't possible to repeat the command. + Prog: nn + Title: Patch 10 broke term.c on BSD based systems + From: too many to mention (sorry)! + Fixed: Patch #11 [term.c] + + Prog: nnadmin + Title: Root was sometimes denied permission to Z)ap (rmgroup) a group. + From: david@cs.uow.edu.au (David E A Wilson) + Fixed: Patch #11 [admin.c] + + Prog: nn + Title: Unsubscribed groups may be included by NEW in sequence. + From: avery@netcom.UUCP (Avery Colter) + Fixed: Patch #11 [sequence.c] + + Prog: nn + Title: 'V' {version} command not supported in reading mode. + From: msc@mtcchi.uucp (Michael S. Cross) + Fixed: Patch #11 [more.c] + + Prog: nn + Title: subject-match-limit confuses qsort() - may even dump core! + From: eggert@twinsun.com (Paul Eggert) + fix!!!! + kravitz%foxtail@ucsd.edu (Jody Kravitz) + Mark Nagel + boutilie@motcid.UUCP (Eric Boutilier) + Nick Holloway + Fixed: Patch #11 [sort.c nn.1] + + Paul Eggert: It is possible to construct headers H,I,J for three + different articles such that H + liz@grian.cps.altadena.ca.us (Liz Allen-Mitchell) + Fixed: Patch #11 [group.c] + + Prog: nn + Title: Compressing an mmdf folder did not save in mmdf format. + From: Curtis Galloway + fix + Fixed: Patch #11 [folder.c save.c] + + Prog: aux + Title: Some "good" messages from inews (various versions) are seen as fatal. + From: heiby@mcdchg.chg.mcd.mot.com (Ron Heiby) + fix + Nick Sayer + fix + Fixed: Patch #11 [aux.sh] + + Prog: nnmaster + Title: The nnmaster should attempt to connect again (-r) rather than stop + in case of network errors when connecting to nntp server. + From: olson%anchor.esd@sgi.com (Dave Olson) + fixes + Fixed: Patch #11 [nntp.c global.c] + New features since initial 6.4.0 release ---------------------------------------- *************** *** 1510,1512 **** --- 1572,1637 ---- generation of Distribution: headers. From: KFS Added: Patch #10 [answer.c variable.c] + + Prog: nn + Title: ~user/ is now expanded in file names + From: bernd@bhpcpd.kembla.oz.au (Bernd Wechner) & KFS + Added: Patch #11 [folder.c] + + Prog: xmakefile + Title: Added support for Symmetry style parallel make + From: Kareth & Jaap Vermeulen + Added: Patch #11 [xmakefile conf/m-symmetry.h] + + Prog: nn + Title: If "check-group-access" is set, access to a group (including + the menu) is now prohibited. + From: KFS on request from David Paul Zimmerman + Added: Patch #11 [db.c variable.c] + + Prog: nn + Title: A variable can now be locked, eg. "lock check-group-access" to + prevent a user from modifying the variable. + From: KFS + Added: Patch #11 [init.c variable.c] + + Prog: nn + Title: The init file "LIB/setup" is now loaded first independent of -I option. + From: KFS on request from David Paul Zimmerman + Added: Patch #11 [init.c] + + Prog: nn + Title: nn will now look for a ".defaultnewsrc" on first startup in the + NEWS_LIB, CLIENT, and DB directories (var: initial-newsrc-file). + From: KFS on request from David Paul Zimmerman + Added: Patch #11 [newsrc.c] + + Prog: nn + Title: Stricter splitting of folders and mail boxes. + From: bernd@bhpcpd.kembla.oz.au (Bernd Wechner) & KFS + Added: Patch #11 [folder.c digest.c variable.c] + + Folders are now split according to the format of the first article in + the folder, i.e. a folder is now either in "standard", "UNIX mail", + or MMDF format, and it is no longer possible to have "mixed" folders. + + Prog: nn + Title: Existing folders are now scanned to determine the proper format for + saved articles (unless the variable 'folder-format-check' is unset.) + From: KFS + Added: Patch #11 [save.c variable.c] + + This means that the variables 'mail-format' and 'mmdf-format' + are only used to determine the format of new folders, or if + 'folder-format-check' is off (if you know only one format is used). + + Prog: nn + Title: Improved rewriting of folders and mail boxes. + From: bernd@bhpcpd.kembla.oz.au (Bernd Wechner) & KFS + Added: Patch #11 [folder.c global.c variable.c] + + The backup folder is now located in the .nn directory (there is a new + variable backup-folder-path to control this), and a folder can now be + rewritten even if the directory is read only. The backup folder is + retained if the keep-backup-folder variable is set. A trace of the + compression process is now shown if trace-folder-packing is set. *** ./LAST/folder.c Mon Jul 16 17:38:41 1990 --- folder.c Sat Sep 29 01:26:59 1990 *************** *** 10,23 **** --- 10,64 ---- #include "news.h" #include "term.h" #include "menu.h" + #include + import char *home_directory; + import int current_folder_type; + import int use_mail_folders; + import int use_mmdf_folders; + export int dont_sort_folders = 0; export char *folder_directory = NULL; + export int folder_rewrite_trace = 1; + export char *backup_folder_path = "BackupFolder~"; + export int keep_backup_folder = 1; + export int convert_folder_mode = 0; /* ignore folder's format on rewrite */ import int fmt_linenum; import char *header_lines; /* + * expand ~[user][/...] form + * src ptr is advanced to last char of user name. + */ + + static char *tilde_expansion(srcp, compl) + char **srcp; + int compl; + { + struct passwd *pwd, *getpwnam(); + register char *name = *srcp; + register char *tail, x; + + tail = ++name; /* skip ~ */ + while (*tail && isascii(*tail) && !isspace(*tail) && *tail != '/') + tail++; + + if (compl && *tail != '/') return NULL; + if (tail == name) return home_directory; + + *srcp = tail - 1; + x = *tail; + *tail = NUL; + pwd = getpwnam(name); + if (pwd == NULL && !compl) + msg("User %s not found", name); + *tail = x; + + return (pwd == NULL) ? NULL : pwd->pw_dir; + } + + /* * file name completion and expansion * * expand_mode bits: *************** *** 25,30 **** --- 66,72 ---- * 2: don't expand $N * 4: don't expand any $? (but $(...) is expanded) * 8: don't complain about ~... (shell will do that) + * 10: doing filename completion */ *************** *** 56,69 **** } if ((expand_mode & 1) && c == '~') { ! if (src[1] != '/') { ! if (expand_mode & 8) goto copy; ! msg("Can't handle ~user expansion (yet)"); return 0; } - cp = home_directory; - cp_str: while (*cp) *dp++ = *cp++; if (dp[-1] != '/') *dp++ = '/'; --- 98,107 ---- } if ((expand_mode & 1) && c == '~') { ! if ((cp = tilde_expansion(&src, (expand_mode & 0x10))) == NULL) { return 0; } cp_str: while (*cp) *dp++ = *cp++; if (dp[-1] != '/') *dp++ = '/'; *************** *** 187,193 **** if (*path == '|') return -1; /* no completion for pipes */ if (*path == '+' || *path == '~') { ! if (!expand_file_name(nbuf, path, 1)) return 0; /* no completions */ } else strcpy(nbuf, path); --- 225,231 ---- if (*path == '|') return -1; /* no completion for pipes */ if (*path == '+' || *path == '~') { ! if (!expand_file_name(nbuf, path, 0x11)) return 0; /* no completions */ } else strcpy(nbuf, path); *************** *** 288,299 **** return ME_NO_REDRAW; } was_raw = no_raw(); s_keyboard = 0; - printf("\rReading: %-.65s", path); - clrline(); - current_group = &fake_group; mark_memory(&mem_marker); --- 326,349 ---- return ME_NO_REDRAW; } + switch (get_folder_type(folder)) { + case 0: + msg("Reading: %-.65s", path); break; + case 1: + case 2: + msg("Reading %s folder: %-.50s", + current_folder_type==1 ? "mail" : "mmdf", path); + break; + default: + msg("Folder is empty"); + fclose(folder); + return ME_NO_REDRAW; + } + rewind(folder); + was_raw = no_raw(); s_keyboard = 0; current_group = &fake_group; mark_memory(&mem_marker); *************** *** 301,307 **** ah = alloc_art(); more = 1; ! while (more && (more = get_digest_article(folder, dgbuf)) >= 0) { if (s_keyboard) break; ah->a_number = 0; --- 351,357 ---- ah = alloc_art(); more = 1; ! while (more && (more = get_digest_article(folder, dgbuf, 1)) >= 0) { if (s_keyboard) break; ah->a_number = 0; *************** *** 346,353 **** fclose(folder); - if (was_raw) raw(); - if (s_keyboard) { menu_cmd = ME_NO_REDRAW; } else --- 396,401 ---- *************** *** 381,387 **** } if (mode == 0 && cancel_count) { clrdisp(); ! printf("Folder: %s\nFile: %s\n\n", folder_name, folder_file); if (cancel_count == n_articles) printf("Cancel all articles and remove folder? "); else --- 429,435 ---- } if (mode == 0 && cancel_count) { clrdisp(); ! printf("\rFolder: %s\n\rFile: %s\n\n\r", folder_name, folder_file); if (cancel_count == n_articles) printf("Cancel all articles and remove folder? "); else *************** *** 393,401 **** case 1: printf("\n\n"); if (cancel_count == n_articles) { ! if (unlink(group_path_name) < 0) { ! printf("Could not unlink %s\n", group_path_name); ! sleep(3); } } else rewrite_folder(); --- 441,450 ---- case 1: printf("\n\n"); if (cancel_count == n_articles) { ! if (unlink(group_path_name) < 0 && ! truncate(group_path_name, (off_t)0) < 0) { ! printf("\rCould not unlink %s\n\r", group_path_name); ! any_key(0); } } else rewrite_folder(); *************** *** 415,420 **** --- 464,471 ---- header_lines = orig_hdr_lines; } + if (was_raw) raw(); + return menu_cmd; } *************** *** 422,496 **** rewrite_folder() { register FILE *src, *dst; ! char oldfile[FILENAME], *sp; register int c; register long cnt; register article_header *ah, **ahp; register article_number n; ! if ((src = fopen(group_path_name, "r")) == NULL) { ! msg("Cannot open %s", group_path_name); ! return; } ! strcpy(oldfile, group_path_name); ! sp = strrchr(oldfile, '/'); ! strcpy((sp == NULL ? oldfile : sp+1), "~OLD~FOLDER~"); ! ! unlink(oldfile); ! if (link(group_path_name, oldfile) < 0) goto move_error; ! if (unlink(group_path_name) < 0) { ! if (unlink(oldfile) == 0) goto move_error; ! printf("\n\n%s was linked to %s --- cannot proceed\n", ! group_path_name, oldfile); ! sleep(5); ! return; } ! if ((dst = fopen(group_path_name, "w")) == NULL) { fclose(src); goto move_back; } sort_articles(0); ! printf("Compressing folder..."); fl; for (ahp = articles, n = n_articles; --n >= 0; ahp++) { ah = *ahp; if (ah->attr == A_CANCEL) continue; fseek(src, ah->hpos, 0); ! cnt = ah->lpos - ah->hpos; while (--cnt >= 0) { if ((c = getc(src)) == EOF) break; putc(c, dst); } ! putc(NL, dst); } fclose(src); ! if (ferror(dst)) { ! fclose(dst); ! goto move_back; ! } ! unlink(oldfile); return; ! move_back: ! if (link(oldfile, group_path_name) == 0) { ! unlink(oldfile); ! printf("Cannot create new file -- Folder restored\n"); ! sleep(2); ! } else { ! printf("Cannot create new file\n\nFolder saved in %s\n", ! oldfile); ! sleep(10); ! } ! return; ! move_error: ! fclose(src); ! printf("\n\nCannot move folder %s to %s\n", ! group_path_name, oldfile); ! sleep(3); ! return; } --- 473,540 ---- rewrite_folder() { register FILE *src, *dst; ! char *oldfile, *sp; register int c; register long cnt; register article_header *ah, **ahp; register article_number n; ! if (strchr(backup_folder_path, '/')) ! oldfile = backup_folder_path; ! else ! oldfile = relative(nn_directory, backup_folder_path); ! ! if (move_file(group_path_name, oldfile, 1) < 0) { ! printf("\r\n\nCannot backup folder in %s\n", oldfile); ! goto confirm; } ! if ((src = open_file(oldfile, OPEN_READ)) == NULL) { ! printf("\rCannot open %s\n\r", oldfile); ! goto move_back; } ! if ((dst = open_file(group_path_name, OPEN_CREATE)) == NULL) { fclose(src); + printf("\rCannot create %s\n\r", group_path_name); goto move_back; } sort_articles(0); ! printf("\rCompressing folder...\n\r"); fl; ! ! get_folder_type(src); for (ahp = articles, n = n_articles; --n >= 0; ahp++) { ah = *ahp; + cnt = ah->lpos - ah->hpos; + if (folder_rewrite_trace) + printf("%s\t%s (%ld-%ld=%ld)\n\r", + ah->attr == A_CANCEL ? "CANCEL" : "KEEP", + ah->subject, (long)(ah->hpos), (long)(ah->lpos), cnt); if (ah->attr == A_CANCEL) continue; fseek(src, ah->hpos, 0); ! mailbox_format(dst, -1); while (--cnt >= 0) { if ((c = getc(src)) == EOF) break; putc(c, dst); } ! mailbox_format(dst, 0); } + fclose(src); ! if (fclose(dst) == EOF) goto move_back; ! if (!keep_backup_folder) unlink(oldfile); ! if (folder_rewrite_trace) goto confirm; return; ! move_back: ! if (move_file(oldfile, group_path_name, 2) == 0) ! printf("Cannot create new file -- Folder restored\n\r"); ! else ! printf("Cannot create new file\n\n\rFolder saved in %s\n\r", oldfile); ! confirm: ! any_key(0); } *** ./LAST/global.c Tue Sep 18 12:44:57 1990 --- global.c Fri Oct 5 18:23:21 1990 *************** *** 39,44 **** --- 39,48 ---- export char version_id[32]; + #ifdef NNTP + export int use_nntp = 0; /* bool: t iff we use nntp */ + #endif + export unsigned short user_eid; export unsigned short user_id, group_id; export int process_id; *************** *** 357,362 **** --- 361,387 ---- return NULL; } + FILE *open_file_search_path(name, mode) + char *name; + int mode; + { + FILE *f; + + if (name == NULL) return NULL; + + if (*name == '/') return open_file(name, mode); + + f = NULL; + if (!use_nntp) + f = open_file(relative(news_lib_directory, name), OPEN_READ); + if (f == NULL) + f= open_file(relative(lib_directory, name), OPEN_READ); + if (f == NULL) + f = open_file(relative(db_directory, name), OPEN_READ); + + return f; + } + fgets_multi(buf, size, f) char *buf; int size; *************** *** 452,462 **** char *name; char *mode; { ! struct stat statb; extern int errno; int mask; ! if (stat(name, &statb)) return 0; if (mode == NULL) return statb.st_mtime; --- 477,487 ---- char *name; char *mode; { ! static struct stat statb; extern int errno; int mask; ! if (name != NULL && stat(name, &statb)) return 0; if (mode == NULL) return statb.st_mtime; *************** *** 499,504 **** --- 524,637 ---- return statb.st_mtime; } + /* + * copy_file: copy (or append) src file to dest file. + * + * Returns number of characters copied or an error code: + * -1: source file not found + * -2: cannot create destination + * -3: write error + */ + + int32 copy_file(src, dest, append) + char *src, *dest; + int append; + { + register FILE *s, *d; + register int32 n = 0; + register int c; + + s = open_file(src, OPEN_READ); + if (s == NULL) return -1; + + d = open_file(dest, append ? OPEN_APPEND : OPEN_CREATE); + if (d == NULL) { + fclose(s); + return -2; + } + + n = 0; + while ((c = getc(s)) != EOF) { + putc(c, d); + n++; + } + + fclose(s); + if (fclose(d) == EOF) { + if (!append) unlink(dest); + return -3; + } + return n; + } + + /* + * move_file: move old file to new file, linking if possible. + * + * The third arg determines what is acceptable if the old file cannot be + * removed after copying to the new file: + * 0: must remove old, else remove new and fail, + * 1: must remove or truncate old, else remove new and fail, + * 2: just leave old if it cannot be removed or truncated. + * + * Returns positive value for success, negative for failure: + * 0: file renamed (link) + * 1: file copied, old removed + * 2: file copied, but old file is only truncated. + * 3: file copied, but old file still exist. + * -1: source file not found + * -2: cannot create destination + * -3: write error + * -4: cannot unlink/truncate old + * -5: cannot unlink new + * -6: cannot link old to new + * -9: messy situation: old and new linked on return (cannot happen?) + */ + + move_file(old, new, may_keep_old) + char *old, *new; + int may_keep_old; + { + int32 n; + + if (file_exist(new, (char *)NULL)) { + if (file_exist((char *)NULL, "d")) + return -5; + if (unlink(new) < 0) /* careful - new may be directory ? */ + switch (errno) { + case ENOENT: + break; + case EACCES: + if (file_exist((char *)NULL, "w")) goto do_copy; + default: + return -5; + } + } + + if (link(old, new) < 0) + switch (errno) { + case EACCES: /* can just as well try to copy */ + case EXDEV: + goto do_copy; + default: + return -6; + } + + if (unlink(old) == 0) + return 0; + + /* we were able to link but not unlink old */ + /* remove new, and attempt a copy instead */ + if (unlink(new) < 0) return -9; /* cannot happen? */ + + do_copy: + if ((n = copy_file(old, new, 0)) < 0) return n; + if (unlink(old) == 0) return 1; + if (may_keep_old) + if (n == 0 || truncate(old, (off_t)0) == 0) return 2; + if (may_keep_old == 2) return 3; + unlink(new); + return -4; + } #ifdef HAVE_SYSLOG #include *************** *** 531,538 **** return 1; } ! static mail_sys_error(err) char *err; { FILE *f; char cmd[FILENAME*2]; --- 664,672 ---- return 1; } ! static mail_sys_error(err, isfatal) char *err; + int isfatal; { FILE *f; char cmd[FILENAME*2]; *************** *** 541,553 **** strcpy(cmd, FATAL_ERROR_MAIL_CMD); #else #ifdef MAILX ! sprintf(cmd, "%s -s 'nnmaster fatal error' %s", MAILX, OWNER); #else sprintf(cmd, "mail %s", OWNER); #endif #endif if ((f = popen(cmd, "w")) == NULL) return; ! fprintf(f, "nnmaster terminated\n\nFatal system error:\n%s\n", err); pclose(f); } --- 675,690 ---- strcpy(cmd, FATAL_ERROR_MAIL_CMD); #else #ifdef MAILX ! sprintf(cmd, "%s -s 'nnmaster %s' %s", MAILX, ! isfatal ? "fatal error" : "warning", OWNER); #else sprintf(cmd, "mail %s", OWNER); #endif #endif if ((f = popen(cmd, "w")) == NULL) return; ! fprintf(f, "nnmaster %s\n\n%system error:\n%s\n", ! isfatal ? "terminated" : "warning", ! isfatal ? "Fatal s" : "S", err); pclose(f); } *************** *** 570,576 **** end_vararg; if (who_am_i == I_AM_MASTER) { ! mail_sys_error(buf); if (dont_write_console) nn_exit(7); #ifndef HAVE_SYSLOG f = open_file("/dev/console", OPEN_CREATE); --- 707,713 ---- end_vararg; if (who_am_i == I_AM_MASTER) { ! mail_sys_error(buf, 1); if (dont_write_console) nn_exit(7); #ifndef HAVE_SYSLOG f = open_file("/dev/console", OPEN_CREATE); *************** *** 587,592 **** --- 724,770 ---- user_error("%s", buf); } + /* + * sys_warning: like sys_error but MASTER will return with -1 + * instead of exit. Clients still terminate! + */ + + /*VARARGS*/ + sys_warning(va_alist) + va_dcl + { + char buf[512]; + char *fmt; + FILE *f; + use_vararg; + + start_vararg; + enter_log('R', va_args1toN); + end_vararg; + + start_vararg; + fmt = va_arg1(char *); + vsprintf(buf, fmt, va_args2toN); + end_vararg; + + if (who_am_i != I_AM_MASTER) + user_error("%s", buf); + + mail_sys_error(buf, 0); + if (dont_write_console) return -1; + #ifndef HAVE_SYSLOG + if((f = open_file("/dev/console", OPEN_CREATE)) != NULL) { + fprintf(f, "\n\rNNMASTER WARNING\n\r%s\n\n\r", buf); + fclose(f); + } + #else /* HAVE_SYSLOG */ + openlog("nnmaster", LOG_CONS, LOG_DAEMON); + syslog(LOG_ALERT, "%s", buf); + closelog(); + #endif /* HAVE_SYSLOG */ + return -1; + } + /*VARARGS*/ log_entry(va_alist) va_dcl *************** *** 770,773 **** --- 948,976 ---- path, mode, path); return system(command) != 0 ? -1 : 0; } + #endif + + #ifndef HAVE_TRUNCATE + + truncate(path, len) + char *path; + off_t len; + { + int fd; + struct stat st; + + if (len != 0) + sys_error("truncate(%s,%ld): non-zero length", path, (long)len); + + #ifdef O_TRUNC + fd = open(path, O_WRONLY | O_TRUNC); + #else + if (stat(path, &st) < 0) return -1; + fd = creat(path, st.st_mode & 07777); + #endif + if (fd < 0) return -1; + close(fd); + return 0; + } + #endif *** ./LAST/group.c Tue Sep 18 12:44:59 1990 --- group.c Mon Sep 24 13:13:59 1990 *************** *** 686,691 **** --- 686,692 ---- msg("Group %s already active", gh->group_name); goto_return(ME_NO_REDRAW); } + if (o_cur_first < 0) o_cur_first = 0; gh->current_first = gh->last_db_article + 1; } *** ./LAST/init.c Thu Jul 19 18:12:14 1990 --- init.c Thu Oct 4 19:04:47 1990 *************** *** 178,183 **** --- 178,187 ---- extern FILE *loc_seq_hook, *glob_seq_hook; char *next_arg; + in_init = 1; + load_init_file(relative(lib_directory, "setup"), (FILE **)NULL, 0); + in_init = 0; + if (first_arg && strncmp(first_arg, "-I", 2) == 0) { if (first_arg[2] == NUL) return; first_arg += 2; *************** *** 240,245 **** --- 244,250 ---- "help", 4, 2, "load", 4, 0, "local", 5, 3, + "lock", 4, 3, "make", 4, -1, "make map ", 9, -2, "man", 3, 0, *************** *** 907,912 **** --- 912,923 ---- CASE( "toggle" ) { if (argv(1) == NULL) goto stx_err; toggle_variable(argv(1)); + break; + } + + CASE( "lock" ) { + if (argv(1) == NULL) goto stx_err; + lock_variable(argv(1)); break; } *** ./LAST/man/nn.1.C Tue Sep 18 12:45:06 1990 --- man/nn.1.C Fri Oct 5 18:43:05 1990 *************** *** 1101,1113 **** .B n command). .TP ! \fBsubject-match-limit\fP \fIlength\fP (integer, default 20) ! If one article's subject is identical to the first part of another ! article, the two subjects will still be considered identical if the ! length of the shorter subject is at least the limit set by this ! variable. This is mainly used to get articles whose subject line has ! been truncated for some reason (who said notefiles?) aligned with the ! proper set of articles anyway. .TP \fBsubject-match-offset\fP \fIoffset\fP (integer, default 0) When set to a positive number, that many characters at the beginning --- 1101,1110 ---- .B n command). .TP ! \fBsubject-match-limit\fP \fIlength\fP (integer, default 256) ! Subjects will be considered identical if their first \fIlength\fP ! characters match. Setting this uncritically to a low value may ! cause unexpected results! .TP \fBsubject-match-offset\fP \fIoffset\fP (integer, default 0) When set to a positive number, that many characters at the beginning *** ./LAST/more.c Tue Sep 18 12:45:08 1990 --- more.c Thu Sep 20 22:05:48 1990 *************** *** 1038,1043 **** --- 1038,1047 ---- if (shell_escape()) goto redraw; goto dflt_prompt; + case K_VERSION: + prompt(P_VERSION); + goto same_prompt; + case K_EXTENDED_CMD: news_save = news; digest_save = digest; *** ./LAST/news.c Thu Jul 19 18:12:20 1990 --- news.c Thu Sep 27 20:27:34 1990 *************** *** 55,61 **** if (fptr = (*hdr_field)(bp, all)) { while (*bp && *bp != ':' && isascii(*bp) && !isspace(*bp)) bp++; ! bp++; while (*bp && isascii(*bp) && isspace(*bp) && *bp != NL) bp++; *fptr = bp; } --- 55,61 ---- if (fptr = (*hdr_field)(bp, all)) { while (*bp && *bp != ':' && isascii(*bp) && !isspace(*bp)) bp++; ! if (*bp) bp++; while (*bp && isascii(*bp) && isspace(*bp) && *bp != NL) bp++; *fptr = bp; } *** ./LAST/newsrc.c Tue Sep 18 12:45:09 1990 --- newsrc.c Thu Oct 4 22:30:46 1990 *************** *** 26,31 **** --- 26,32 ---- export int keep_rc_backup = 1; export char *bak_suffix = ".bak"; + export char *initial_newsrc_path = ".defaultnewsrc"; export int no_update = 0; export int use_selections = 1; *************** *** 337,343 **** } rc = open_file(newsrc_file, OPEN_READ); ! if (rc == NULL) goto new_user; while (fgets(rcbuf, RC_LINE_MAX, rc) != NULL) { gh = NULL; --- 338,351 ---- } rc = open_file(newsrc_file, OPEN_READ); ! if (rc == NULL) { ! extern FILE *open_file_search_path(); ! rc = open_file_search_path(initial_newsrc_path, OPEN_READ); ! if (rc == NULL) goto new_user; ! /* ignore groups not in the initial newsrc file */ ! last_new_gh = ACTIVE_GROUP(master.number_of_groups - 1); ! last_new_group = last_new_gh->creation_time; ! } while (fgets(rcbuf, RC_LINE_MAX, rc) != NULL) { gh = NULL; *** ./LAST/nntp.c Thu Jul 19 18:12:21 1990 --- nntp.c Fri Oct 5 18:23:22 1990 *************** *** 47,53 **** import char *db_directory, *tmp_directory, *news_active; export char nntp_server[256]; /* name of nntp server */ - export int use_nntp = 0; /* bool: t iff we use nntp */ export int nntp_failed = 0; /* bool: t iff connection is broken in nntp_get_article() or nntp_get_active() */ --- 47,52 ---- *************** *** 63,68 **** --- 62,68 ---- import char *sys_errlist[]; extern int user_error(); extern int sys_error(); + extern int sys_warning(); #define syserr() (errno >= 0 && errno < sys_nerr ? \ sys_errlist[errno] : "Unknown error.") *************** *** 259,265 **** /* * get_socket: get a connection to the nntp server. * ! * Doesn't return in case of errors. */ static get_socket() --- 259,268 ---- /* * get_socket: get a connection to the nntp server. * ! * Errors can happen when YP services or DNS are temporarily down or ! * hung, so we log errors and return failure rather than exitting if we ! * are the master. The effects of retrying every 15 minutes (or whatever ! * the -r interval is) are not that bad. Dave Olson, SGI */ static get_socket() *************** *** 276,287 **** #endif if ((sp = getservbyname("nntp", "tcp")) == NULL) ! sys_error("nntp/tcp: Unknown service.\n"); s = who_am_i == I_AM_MASTER ? 10 : 2; while ((hp = gethostbyname(nntp_server)) == NULL) { ! if (--s < 0) ! sys_error("NNTP server %s unknown.\n", nntp_server); sleep(10); } --- 279,289 ---- #endif if ((sp = getservbyname("nntp", "tcp")) == NULL) ! return sys_warning("nntp/tcp: Unknown service.\n"); s = who_am_i == I_AM_MASTER ? 10 : 2; while ((hp = gethostbyname(nntp_server)) == NULL) { ! if (--s < 0) goto host_err; sleep(10); } *************** *** 300,309 **** #ifdef h_addr /* get a socket and initiate connection -- use multiple addresses */ for (cp = hp->h_addr_list; cp && *cp; cp++) { s = socket(hp->h_addrtype, SOCK_STREAM, 0); ! if (s < 0) ! sys_error("Can't get NNTP socket: %s\n", syserr()); bcopy(*cp, (char *)&sin.sin_addr, hp->h_length); x = connect(s, (struct sockaddr *)&sin, sizeof (sin)); --- 302,311 ---- #ifdef h_addr /* get a socket and initiate connection -- use multiple addresses */ + s = x = -1; for (cp = hp->h_addr_list; cp && *cp; cp++) { s = socket(hp->h_addrtype, SOCK_STREAM, 0); ! if (s < 0) goto sock_err; bcopy(*cp, (char *)&sin.sin_addr, hp->h_length); x = connect(s, (struct sockaddr *)&sin, sizeof (sin)); *************** *** 314,352 **** (void) close(s); s = -1; } ! if (x < 0 && who_am_i != I_AM_MASTER) ! user_error("Giving up on NNTP server %s!\n", nntp_server); #else /* no name server */ #ifdef EXCELAN if ((s = socket(SOCK_STREAM, NULL, &sin, SO_KEEPALIVE)) < 0) ! sys_error("Can't get NNTP socket: %s", syserr()); ! sin.sin_port = htons(IPPORT_NNTP); machine = nntp_server; ! if ((sin.sin_addr.s_addr = rhost(&machine)) == -1) ! sys_error("%s: Unknown host.", nntp_server); /* And then connect */ ! if (connect(s, &sin) < 0) { ! if (who_am_i == I_AM_MASTER) ! sys_error("Connecting to %s: %s", nntp_server, syserr()); ! (void) close(s); ! s = -1; ! } #else /* not EXCELAN */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) ! sys_error("Can't get NNTP socket: %s\n", syserr()); ! /* And then connect */ bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length); ! if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { ! if (who_am_i == I_AM_MASTER) ! sys_error("Connecting to %s failed: %s", nntp_server, syserr()); ! s = -1; ! } #endif /* EXCELAN */ #endif return s; } /* --- 316,363 ---- (void) close(s); s = -1; } ! if (x < 0) ! sys_warning("Giving up on NNTP server %s!", nntp_server); #else /* no name server */ #ifdef EXCELAN if ((s = socket(SOCK_STREAM, NULL, &sin, SO_KEEPALIVE)) < 0) ! goto sock_err; ! sin.sin_port = htons(IPPORT_NNTP); machine = nntp_server; ! if ((sin.sin_addr.s_addr = rhost(&machine)) == -1) { ! (void) close(s); ! goto host_err; ! } /* And then connect */ ! if (connect(s, &sin) < 0) ! goto conn_err; #else /* not EXCELAN */ if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) ! goto sock_err; ! /* And then connect */ bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length); ! if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) ! goto conn_err; #endif /* EXCELAN */ #endif return s; + + host_err: + sys_warning("NNTP server %s unknown.\n", nntp_server); + return -1; + + sock_err: + sys_warning("Can't get NNTP socket: %s", syserr()); + return -1; + + conn_err: + (void) close(s); + if (who_am_i == I_AM_MASTER) + sys_warning("Connecting to %s failed: %s", nntp_server, syserr()); + return -1; } /* *** ./LAST/patchlevel.h Tue Sep 18 12:45:13 1990 --- patchlevel.h Thu Oct 4 23:12:18 1990 *************** *** 21,27 **** * 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 --- 21,28 ---- * 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 + * 1990-10-05: Patch #11 (6.4.11) - HIGH */ ! #define PATCHLEVEL 11 *** ./LAST/save.c Tue Sep 18 12:45:14 1990 --- save.c Mon Oct 1 17:15:46 1990 *************** *** 22,27 **** --- 22,28 ---- export int quick_save = 0; export int conf_append = 0; export int conf_create = 1; + export int folder_format_check = 1; export char *saved_header_escape = "~"; *************** *** 47,52 **** --- 48,55 ---- import int shell_restrictions; import char delayed_msg[]; + import int current_folder_type; + import int rot13_active; static int save_mode; *************** *** 151,156 **** --- 154,173 ---- return 1; } + set_folder_type(name) + char *name; + { + FILE *f; + + current_folder_type = -1; + if (!folder_format_check) return; + + if ((f = open_file(name, OPEN_READ)) != NULL) { + get_folder_type(f); + fclose(f); + } + } + char *init_save(command, mode_textp) char command; char **mode_textp; *************** *** 487,494 **** fclose(art); return 0; } ! if (ftell(save_file) != (off_t)0) save_mode &= ~FILE_IS_NEW; } } --- 504,514 ---- fclose(art); return 0; } ! current_folder_type = -1; ! if (ftell(save_file) != (off_t)0) { ! if (mode != NO_HEADER) set_folder_type(save_name); save_mode &= ~FILE_IS_NEW; + } } } *************** *** 627,632 **** --- 647,656 ---- return; } fseek(h, (off_t)0, 2); + if (ftell(h) > 0) + set_folder_type(file); + else + current_folder_type = -1; if (!use_mmdf_folders && ftell(h) > 0) putc(NL, h); /* just in case */ mailbox_format(h, 1); endpos = ftell(f) - ah->hpos; *************** *** 644,651 **** { time_t now; char *ctime(); ! if (use_mmdf_folders) { fprintf(f, "\001\001\001\001\n"); return 0; } --- 668,692 ---- { time_t now; char *ctime(); + int do_mmdf, do_mail; + + do_mmdf = do_mail = 0; + switch (current_folder_type) { + case 0: + break; + case 1: + do_mail = 1; + break; + case 2: + do_mmdf = 1; + break; + default: + do_mmdf = use_mmdf_folders; + do_mail = use_mail_folders; + break; + } ! if (do_mmdf) { fprintf(f, "\001\001\001\001\n"); return 0; } *************** *** 655,661 **** return 1; } ! if (use_mail_folders) { now = cur_time(); fprintf(f, "From %s %s", (use_path_in_from && news.ng_path) ? news.ng_path : --- 696,702 ---- return 1; } ! if (top > 0 && do_mail) { now = cur_time(); fprintf(f, "From %s %s", (use_path_in_from && news.ng_path) ? news.ng_path : *** ./LAST/sequence.c Tue Sep 18 12:45:14 1990 --- sequence.c Wed Sep 19 18:40:55 1990 *************** *** 669,674 **** --- 669,675 ---- case GS_NEW_GROUP: if ((gh->group_flag & G_NEW) == 0) continue; + if (gh->group_flag & G_UNSUBSCRIBED) continue; break; case GS_PREFIX0: *** ./LAST/sort.c Tue Sep 18 12:45:15 1990 --- sort.c Thu Oct 4 22:27:30 1990 *************** *** 9,15 **** --- 9,24 ---- + #ifdef BAD_ORDER_SUBJ_DATE + /* If one article's subject is identical to the first part of another + article, the two subjects will still be considered identical if the + length of the shorter subject is at least the limit set by this variable. */ export int subject_match_limit = 20; /* "strncmp" limit for subjects */ + #else + /* Subjects are considered identical if their first s-m-l characters match */ + export int subject_match_limit = 256; /* "strncmp" limit for subjects */ + #endif + export int match_skip_prefix = 0; /* skip first N bytes in matches */ export int match_parts_equal = 0; /* match digits as equal */ *************** *** 78,95 **** --- 87,112 ---- } } + #ifdef BAD_ORDER_SUBJ_DATE for (len = 0; ; len++, a++, b++) { + #else + for (len = subject_match_limit; --len >= 0; a++, b++) { + #endif while ((ca = *a) && MATCH_DROP(match_subject, ca)) a++; while ((cb = *b) && MATCH_DROP(match_subject, cb)) b++; if (ca == NUL) { if (cb == NUL) break; + #ifdef BAD_ORDER_SUBJ_DATE if (len >= subject_match_limit) break; + #endif return -1; } if (cb == NUL) { + #ifdef BAD_ORDER_SUBJ_DATE if (len >= subject_match_limit) break; + #endif return 1; } *** ./LAST/term.c Tue Sep 18 12:45:16 1990 --- term.c Tue Sep 18 15:33:39 1990 *************** *** 825,832 **** --- 825,834 ---- do_flush_input = 1; #else #ifdef FREAD + { int arg = FREAD; ioctl(0, TIOCFLUSH, &arg); + } #else ioctl(0, TIOCFLUSH, 0); #endif *** ./LAST/variable.c Tue Sep 18 12:45:17 1990 --- variable.c Thu Oct 4 23:12:16 1990 *************** *** 11,16 **** --- 11,17 ---- import in_init; import char /* string variables */ + *backup_folder_path, *bak_suffix, *bug_address, *decode_header_file, *************** *** 26,31 **** --- 27,33 ---- *folder_directory, included_mark[], *inews_program, + *initial_newsrc_path, *mail_box, *mail_record, *mail_script, *************** *** 60,65 **** --- 62,68 ---- auto_select_subject, auto_preview_mode, case_fold_search, + check_group_access, compress_mode, conf_append, conf_auto_quit, *************** *** 81,91 **** --- 84,97 ---- flow_control, flush_typeahead, fmt_rptsubj, + folder_format_check, + folder_rewrite_trace, ignore_xon_xoff, include_art_id, include_full_header, include_mark_blanks, inews_pipe_input, + keep_backup_folder, keep_rc_backup, keep_unsubscribed, keep_unsub_long, *************** *** 163,168 **** --- 169,175 ---- scroll_last_lines, show_purpose_mode, slow_speed, + strict_from_parse, sort_mode, subject_match_limit, wrap_headers; *************** *** 200,205 **** --- 207,213 ---- #define V_SAFE 0x0100 #define V_INIT 0x0200 + #define V_LOCKED 0x0800 #define V_MODIFIED 0x8000 #define STR V_STRING | *************** *** 232,240 **** --- 240,250 ---- "auto-read-mode-limit", INT 0, (char **)&auto_read_limit, "auto-select-subject", BOOL 0, (char **)&auto_select_subject, "backup", BOOL 0, (char **)&keep_rc_backup, + "backup-folder-path", STR 4, (char **)&backup_folder_path, "backup-suffix", STR 0, (char **)&bak_suffix, "bug-report-address", STR 0, (char **)&bug_address, "case-fold-search", BOOL 0, (char **)&case_fold_search, + "check-group-access", BOOL 0, (char **)&check_group_access, "collapse-subject", INT 3, (char **)&collapse_subject, "columns", INT 1, (char **)&Columns, "comp1-key", KEY 0, (char **)&comp1_key, *************** *** 272,279 **** --- 282,291 ---- "flow-control", BOOL 0, (char **)&flow_control, "flush-typeahead", BOOL 0, (char **)&flush_typeahead, "folder", STR 2, (char **)&folder_directory, + "folder-format-check", BOOL 0, (char **)&folder_format_check, "folder-save-file", STR 3, (char **)&folder_save_file, "follow-distribution", STR 0, (char **)&distribution_follow, + "from-line-parsing", INT 0, (char **)&strict_from_parse, "fsort", BOOL 2, (char **)&dont_sort_folders, "header-lines", STR 0, (char **)&header_lines, "help-key", KEY 0, (char **)&help_key, *************** *** 284,289 **** --- 296,303 ---- "included-mark", STR 1, (char **)included_mark, "inews", STR 0, (char **)&inews_program, "inews-pipe-input", BOOL 0, (char **)&inews_pipe_input, + "initial-newsrc-file", STR 0, (char **)&initial_newsrc_path, + "keep-backup-folder", BOOL 0, (char **)&keep_backup_folder, "keep-unsubscribed", BOOL 0, (char **)&keep_unsubscribed, "kill", BOOL 0, (char **)&do_kill_handling, "kill-debug", BOOL 0, (char **)&kill_debug, *************** *** 375,380 **** --- 389,395 ---- "suggest-default-save", BOOL 0, (char **)&suggest_save_file, "tidy-newsrc", BOOL 0, (char **)&tidy_newsrc, "time", BOOL 0, (char **)&show_current_time, + "trace-folder-packing", BOOL 0, (char **)&folder_rewrite_trace, "trusted-escape-codes", STR 0, (char **)&trusted_escapes, "unshar-command", STR SAFE 1, (char **)unshar_command, "unshar-header-file", STR 0, (char **)&unshar_header_file, *************** *** 496,501 **** --- 511,521 ---- } } + if (var->var_flags & V_LOCKED) { + msg("Variable '%s' is locked", variable); + return 0; + } + if (!on || val_string == NULL) value = 0; else *************** *** 531,540 **** --- 551,568 ---- break; case 3: + case 4: if (!on || val_string == NULL) { msg("Cannot unset string `%s'", variable); break; } + if (VAR_OP == 4) { + char exp_buf[FILENAME]; + if (expand_file_name(exp_buf, val_string, 1)) { + STR_VAR = copy_str(exp_buf); + break; + } + } STR_VAR = copy_str(val_string); break; } *************** *** 670,675 **** --- 698,712 ---- BOOL_VAR = !BOOL_VAR; } + lock_variable(variable) + char *variable; + { + register struct variable_defs *var; + + if ((var = lookup_variable(variable)) != NULL) + var->var_flags |= V_LOCKED; + } + static char *var_value(var, tag) register struct variable_defs *var; *************** *** 681,686 **** --- 718,724 ---- if (tag != NULL) *tag = var_on_stack(var) ? '>' : + (var->var_flags & V_LOCKED) ? '!' : (var->var_flags & V_MODIFIED) ? '*' : ' '; switch (VAR_TYPE) { *************** *** 898,903 **** --- 936,942 ---- case 0: /* if we update one of these variables, */ case 2: /* new storage will be allocated for it */ case 3: /* so it is ok just to save the pointer */ + case 4: vs->value.str = STR_VAR; break; *************** *** 956,961 **** --- 995,1001 ---- case 0: /* only restore the string if changed; then we */ case 2: /* can also free the memory occupied by the */ case 3: /* 'new' value (if not NULL) */ + case 4: if (STR_VAR != vs->value.str) { if (STR_VAR != NULL) freeobj(STR_VAR); STR_VAR = vs->value.str; *** ./LAST/xmakefile Tue Jun 12 11:47:04 1990 --- xmakefile Wed Aug 22 20:16:40 1990 *************** *** 24,29 **** --- 24,38 ---- #define NNTP_EXTRA_LIB #endif + * Symmetry style parallel make + + #undef PARALLEL + #ifdef PARALLEL_MAKE + #define PARALLEL & + #else + #define PARALLEL + #endif + #ifdef HAVE_ROUTING #define NNMAIL #else *************** *** 53,59 **** * BIN_PROG = nn NNMAIL nnusage nngrab nnstats ACCOUNT ! BIN_LINK = nncheck nnadmin nntidy nngoback nngrep nnpost LIB_PROG = aux upgrade_rc MASTER_PROG = nnmaster back_act nnspew --- 62,68 ---- * BIN_PROG = nn NNMAIL nnusage nngrab nnstats ACCOUNT ! BIN_LINK = nncheck nnadmin nntidy nngoback nngrep nnpost nnbatch LIB_PROG = aux upgrade_rc MASTER_PROG = nnmaster back_act nnspew *************** *** 85,99 **** master: $(MASTER_PROG) inst ! nn: $(NN) @echo linking nn @$(CC) $(CFLAGS) $(NN) -o nn TERMLIB EXTRA_LIB NNTP_EXTRA_LIB ! nnmaster: $(MASTER) @echo linking nnmaster @$(CC) $(CFLAGS) $(MASTER) -o nnmaster EXTRA_LIB NNTP_EXTRA_LIB ! nnmail: $(MAIL) @echo linking nnmail @$(CC) $(CFLAGS) $(MAIL) EXTRA_LIB -o nnmail --- 94,108 ---- master: $(MASTER_PROG) inst ! nn: PARALLEL $(NN) @echo linking nn @$(CC) $(CFLAGS) $(NN) -o nn TERMLIB EXTRA_LIB NNTP_EXTRA_LIB ! nnmaster: PARALLEL $(MASTER) @echo linking nnmaster @$(CC) $(CFLAGS) $(MASTER) -o nnmaster EXTRA_LIB NNTP_EXTRA_LIB ! nnmail: PARALLEL $(MAIL) @echo linking nnmail @$(CC) $(CFLAGS) $(MAIL) EXTRA_LIB -o nnmail *************** *** 112,118 **** upgrade_rc: upgrade_rc.sh prefix cat prefix upgrade_rc.sh > upgrade_rc ; chmod +x upgrade_rc ! nnacct: $(ACCT) @echo linking nnacct @$(CC) $(CFLAGS) $(ACCT) EXTRA_LIB -o nnacct --- 121,127 ---- upgrade_rc: upgrade_rc.sh prefix cat prefix upgrade_rc.sh > upgrade_rc ; chmod +x upgrade_rc ! nnacct: PARALLEL $(ACCT) @echo linking nnacct @$(CC) $(CFLAGS) $(ACCT) EXTRA_LIB -o nnacct *************** *** 125,131 **** prefix: config.h mkprefix ./mkprefix prefix < /dev/null > prefix ! mkprefix: prefix.o global.o $(CC) $(CFLAGS) prefix.o global.o EXTRA_LIB -o mkprefix * --- 134,140 ---- prefix: config.h mkprefix ./mkprefix prefix < /dev/null > prefix ! mkprefix: PARALLEL prefix.o global.o $(CC) $(CFLAGS) prefix.o global.o EXTRA_LIB -o mkprefix *