diff -ruNP xrn-9.01/CREDITS xrn-9.02/CREDITS --- xrn-9.01/CREDITS Sun Mar 22 10:47:49 1998 +++ xrn-9.02/CREDITS Wed Jan 6 21:48:40 1999 @@ -116,6 +116,10 @@ uri@watson.ibm.com Olivier David Kevin Brannen +Mark Hayter +Greg Ubben +Serge Noiraud +"Len Makin" ************************* diff -ruNP xrn-9.01/ChangeLog xrn-9.02/ChangeLog --- xrn-9.01/ChangeLog Mon May 25 10:34:04 1998 +++ xrn-9.02/ChangeLog Fri Sep 24 10:24:17 1999 @@ -1,3 +1,71 @@ +1999-09-24 Jonathan I. Kamens + + Significant user-visible changes in XRN 9.02: + + + Enhancements: + + * XRN 9.02 is believed to be Y2K-compliant. The maintainer of XRN + knows of no Y2K-related problems in this release of XRN. Previous + releases of XRN did, in fact, have Y2K-related problems. + + * XRN 9.02 is now really compliant with the Good Net-Keeping Seal + of Approval. See for + general information about the GNKSA, or + + for the GNKSA review of XRN. Although the maintainer of XRN + thought that 9.01 was compliant (and so stated when 9.01 was + released), there were some actually some problems, which have been + fixed. XRN has been awarded GNKSA seal number 14. The following + user-visible changes were made to achieve GNKSA compliance in XRN + 9.02: + + ** Additional checking of the syntax of "From" lines in outgoing + E-mail messages and newsgroup postings has been added. Rather + than relying on sendmail to do syntax checking, there are now + internal checks of the format of "From" lines. This is necessary + because sendmail will not catch all "From" line format errors. + + ** The default prefix for included text in followups and responses + has been changed from "|> " to ">". + + * KILL files can now search on the "Approved" header in addition + to the other headers which were previously supported (see the XRN + man page for a complete list of supported headers). + + * Two new kill-file commands have been added. The 't' and 'T' + commands adds a kill-file entry for the killed article's + sub-thread or thread (respectively) to the group's kill file. + + * A new XRN X resource, "authenticateOnConnect", has been added. + When it is set to true, XRN will always authenticate to the News + server upon start-up, rather than waiting until the News server + asks for authentication. This is necessary to support News + servers which aren't smart enough to ask the client for + authentication when they should or which allow partial access + without authentication and additional access with authentication. + + * The XRN tar distribution now unpacks in its own directory rather + than the current working directory. + + + Bug fixes: + + * When entering a newsgroup with no unread articles with the "Goto + group" command, XRN would sometimes get confused and enter a + broken state, displaying article mode with no articles and + refusing to exit from it. This has been fixed. + + * Minor changes have been made to make XRN compile cleanly on + recent versions of Linux, FreeBSD, IRIX, Ultrix. + + * Minor changes have been made to make XRN compile cleanly when + linking against INN client libraries. + + * Minor changes has been made to work around gcc and/or Xt bugs. + + * Some messages in the German XRN message table have been updated. + 1998-05-25 Jonathan I. Kamens * Significant user-visible changes in XRN 9.01: @@ -1151,4 +1219,4 @@ Always include article text when calling an external editor command. Fix from per@erix.ericsson.se (Per Hedeland). -# $Id: ChangeLog,v 1.127 1998/05/25 14:34:03 jik Exp $ +# $Id: ChangeLog,v 1.132 1999/09/24 14:24:16 jik Exp $ diff -ruNP xrn-9.01/Imakefile xrn-9.02/Imakefile --- xrn-9.01/Imakefile Wed Jan 28 22:06:12 1998 +++ xrn-9.02/Imakefile Wed Sep 1 21:11:44 1999 @@ -1,5 +1,5 @@ /* - * $Id: Imakefile,v 1.124 1998/01/29 03:05:57 jik Exp $ + * $Id: Imakefile,v 1.125 1999/09/02 01:11:44 jik Exp $ * * xrn - an X-based NNTP news reader * @@ -161,21 +161,6 @@ /* * You probably don't need to change anything in this block. */ - -#ifdef OV_CAMBRIDGE -LEX = flex -SITE_DEFINES += -DOV_CAMBRIDGE -I. -IMAKE_DEFINES += -DOV_CAMBRIDGE -ifeq ($(findstring gcc,$(CC)),gcc) -CDEBUGFLAGS = -g -Wall -DGCC_WALL -pedantic -endif -REGEX_OBJS = /tools/lib/gnuregex.o - -depend:: regex.h - -regex.h: /tools/include/gnuregex.h - ln -s /tools/include/gnuregex.h regex.h -#endif /* OV_CAMBRIDGE */ #ifdef FreeBSDArchitecture EXTRA_LIBRARIES += -lgnuregex diff -ruNP xrn-9.01/Makefile xrn-9.02/Makefile --- xrn-9.01/Makefile Thu Jan 29 16:31:25 1998 +++ xrn-9.02/Makefile Tue Sep 7 10:40:54 1999 @@ -2,7 +2,7 @@ # $TOG: imake.c /main/97 1997/06/20 20:23:51 kaleb $ # ---------------------------------------------------------------------- -# Makefile generated from "Imake.tmpl" and +# Makefile generated from "Imake.tmpl" and # $TOG: Imake.tmpl /main/245 1997/05/20 10:05:47 kaleb $ # # @@ -33,7 +33,7 @@ # platform: $TOG: linux.cf /main/36 1997/06/16 22:21:03 kaleb $ # platform: $XFree86: xc/config/cf/linux.cf,v 3.57.2.10 1997/07/28 14:17:25 dawes Exp $ -# operating system: Linux 2.0.33 i586 [ELF] (2.0.33) +# operating system: Linux 2.0.36 i586 [ELF] (2.0.36) # libc: (5.1073770848.0) # binutils: (28) diff -ruNP xrn-9.01/README xrn-9.02/README --- xrn-9.01/README Thu Jan 15 08:33:19 1998 +++ xrn-9.02/README Fri Sep 24 12:42:44 1999 @@ -17,6 +17,18 @@ Rick Spickelmier. + XRN is a Usenet-friendly News reader! + + I have striven to make XRN adhere to all relevant standards and to +help users avoid the common pitfalls of participation in the Usenet. +To that end, all releases of XRN starting with 9.02 are compliant with +the Good Net-Keeping Seal of Approval (GNKSA), a standard which +defines how News readers should behave to make the Usenet a better +place for everyone. See for +more information about the GNKSA. XRN's GNKSA review can be viewed at +. + + Where to get XRN The XRN home page is . @@ -264,4 +276,4 @@ Jonathan Kamens jik@kamens.brookline.ma.us -# $Id: README,v 1.49 1998/01/15 13:33:19 jik Exp $ +# $Id: README,v 1.50 1999/09/24 16:42:44 jik Exp $ diff -ruNP xrn-9.01/TODO xrn-9.02/TODO --- xrn-9.01/TODO Tue May 12 07:34:15 1998 +++ xrn-9.02/TODO Wed Aug 25 22:06:46 1999 @@ -1,9 +1,51 @@ -$Id: TODO,v 1.199 1998/05/12 11:34:15 jik Exp $ +$Id: TODO,v 1.213 1999/08/26 02:06:46 jik Exp $ The Ever growing list of things that should be done and things that would be nice if they were done.... (and even worse, it's not up to date) +- The "artPost" composition pane should have a button to switch to + "Post and mail". +- It should be possible to wrap included text, paying attention to the + included text prefix when doing so. +- Warn the user if a message being sent or posted contains long lines. +- XRN should strip empty headers before sending messages. +- By default, including article text in a followup or reply should not + include the signature. To allow the signature to be included, two + features should be available: + + - A modifier hey held down when the "Include article" button is + pressed to tell XRN to include everything. + - The user should be allowed to highlight the text he wants to + include and then click on a button to include just that text. +- In "all groups" mode, the "Post" and "Post & Mail" buttons post to + whatever newsgroup the cursor is currently over. I'm not convinced + this is correct behavior; I suspect that like Newsgroup mode, they + should put up a blank template and let the user specify the group to + which to post. +- Need to support INN 2. +- Allow various header fields (configurable) in a displayed message to + be in a different font, different color, different size, etc. +- Add an option to hide identical Subject lines in the article + summary, so that users can scan the summary quickly to find the + various Subject lines in a group. Suggested by Karl Kleinpaste + . +- When a message is put in the info line while a dialog is popped up + (e.g., the dialog with the "Cancel search" button in it), and then + the dialog is popped down, if the mouse is over one of the buttons, + the message in the info line will immediately disappear because of + the enter event generated when the dialog goes away. Proposed fix: + Keep track of the time at which messages are put into the info line, + and require that a message remain in the info line for some number + of seconds before allowing the button documentation strings to start + appearing again. +- Log the date in the Information window when it chanegs, so that it's + possible to tell the dates as well as times of all messages in the + window. Suggested by bri@whitestone.com (Brian Rice). +- Allow Reply-To to be set differently for News and Mail messages. +- Add a kill-file command for dynamically creating a new kill-file + entry (e.g., "when you see a message by this author, kill its + subthread," but more general than that). - Allow the user to retry after mistyping his NNTP password. - Allow users to Supersede their own articles, similar to their current ability to cancel their own articles. @@ -100,10 +142,9 @@ - Make the attribution lines in followups and replies customizable. - Line-break attribution lines if they're too long. (suggested by Paul Menage ). -- Improvements to the follow-up code: - - Fix up the action of "Followup & Reply" so it only includes mail - headers in the mail message and news headers in the posting, and - comments out other headers with "X-" or something. +- Fix up the posting code so it only includes mail headers in the mail + message and news headers in the posting, and comments out other + headers with "X-" or removes some of them completely or something. - Is it really necessary to copy the .newsrc file instead of renaming it? Need to look into this, find out if renaming is sufficient, and if so, modify the code to rename instead of copying. diff -ruNP xrn-9.01/XRn.src xrn-9.02/XRn.src --- xrn-9.01/XRn.src Mon May 25 11:12:43 1998 +++ xrn-9.02/XRn.src Fri Sep 24 10:23:43 1999 @@ -1,8 +1,8 @@ ! -! $Id: XRn.src,v 1.178 1998/05/25 15:12:43 jik Exp $ +! $Id: XRn.src,v 1.183 1999/09/24 14:23:43 jik Exp $ ! -MOTIFxAPP_CLASSx.version: 9.01 (Motif) -XAWxAPP_CLASSx.version: 9.01 +MOTIFxAPP_CLASSx.version: 9.02 (Motif) +XAWxAPP_CLASSx.version: 9.02 xAPP_CLASSx.Geometry: 680x700 *breakLength: 0 *font: 8x13 diff -ruNP xrn-9.01/artMode.c xrn-9.02/artMode.c --- xrn-9.01/artMode.c Mon Mar 23 07:51:50 1998 +++ xrn-9.02/artMode.c Tue Jul 7 07:45:18 1998 @@ -853,7 +853,8 @@ for (i = FirstListedArticle + 1; i <= newsgroup->last; i++) { art = artStructGet(newsgroup, i, False); if (IS_AVAIL(art) && IS_UNREAD(art)) { - struct article copy = *art; + struct article copy; + copy = *art; SET_LISTED(©); artStructReplace(newsgroup, &art, ©, i); } @@ -2128,7 +2129,8 @@ cur_val = *(char **)((char *)art + target_offset); if (! cur_val) { /* XXX See above. */ - struct article copy = *art; + struct article copy; + copy = *art; mesgPane(XRN_SERIOUS, 0, ART_NOT_AVAIL_MSG, artNum); TextRemoveLine(SubjectText, left); removeLine(SubjectString, &left); @@ -2274,37 +2276,6 @@ event, string, count, True); } -static char *getFirstReference _ARGUMENTS((char *)); - -static char *getFirstReference(references) - char *references; -{ - static char *ref_buf = NULL; - static int buf_size = 0; - char *lbrace, *rbrace; - - if (! (references && *references)) - return NULL; - - if (! (lbrace = strchr(references, '<'))) - return NULL; - - if (! (rbrace = strchr(lbrace, '>'))) - return NULL; - - rbrace++; - - if (rbrace - lbrace + 1 > buf_size) { - buf_size = rbrace - lbrace + 1; - ref_buf = XtRealloc(ref_buf, buf_size); - } - - strncpy(ref_buf, lbrace, rbrace - lbrace); - ref_buf[rbrace - lbrace] = '\0'; - - return ref_buf; -} - void artKillThreadFunction(widget, event, string, count) Widget widget; XEvent *event; @@ -2357,7 +2328,7 @@ TextUnsetSelection(SubjectText); if ((int) client_data == XRNgotoArticle_ABORT) { - goto finished; + goto finishedl; } else if ((int) client_data == XRNgotoArticle_DEFAULT) { artNum = CurrentGroup->first; @@ -2373,7 +2344,7 @@ artNum = atol(numberstr); if (! artNum) { mesgPane(XRN_SERIOUS, 0, BAD_ART_NUM_MSG, numberstr); - goto finished; + goto finishedl; } if (*numberstr == '+') artNum = MAX(FirstListedArticle - artNum, CurrentGroup->first); @@ -2422,7 +2393,7 @@ setListSorted(True); } -finished: +finishedl: if (GotoArticleBox) { PopDownDialog(GotoArticleBox); GotoArticleBox = 0; diff -ruNP xrn-9.01/artstruct.c xrn-9.02/artstruct.c --- xrn-9.01/artstruct.c Tue Jul 1 18:57:48 1997 +++ xrn-9.02/artstruct.c Sun Jan 3 10:34:23 1999 @@ -213,6 +213,7 @@ COPY_FIELD(date); COPY_FIELD(id); COPY_FIELD(xref); + COPY_FIELD(approved); COPY_FIELD(references); new->file = reference->file; new->base_file = reference->base_file; @@ -241,6 +242,7 @@ COPY_FIELD(date); COPY_FIELD(id); COPY_FIELD(xref); + COPY_FIELD(approved); COPY_FIELD(references); new->file = reference->file; new->base_file = reference->base_file; @@ -296,6 +298,7 @@ same in both structures. */ CHECK(id, (*art)->previous, *art); CHECK(xref, (*art)->previous, *art); + CHECK(approved, (*art)->previous, *art); CHECK(references, (*art)->previous, *art); (*art)->previous->next = (*art)->next; @@ -319,6 +322,7 @@ same in both structures. */ CHECK(id, (*art)->next, *art); CHECK(xref, (*art)->next, *art); + CHECK(approved, (*art)->next, *art); CHECK(references, (*art)->next, *art); (*art)->next->first = (*art)->first; @@ -371,6 +375,7 @@ } CHECK(id, copy, *original); CHECK(xref, copy, *original); + CHECK(approved, copy, *original); CHECK(references, copy, *original); artStructSet(newsgroup, original); } @@ -542,6 +547,7 @@ ARTSTRCMP(date); ARTSTRCMP(id); ARTSTRCMP(xref); + ARTSTRCMP(approved); ARTSTRCMP(references); if (art1->file != art2->file) diff -ruNP xrn-9.01/clientlib.c xrn-9.02/clientlib.c --- xrn-9.01/clientlib.c Thu Jun 5 07:11:40 1997 +++ xrn-9.02/clientlib.c Fri Jul 10 09:38:44 1998 @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: clientlib.c,v 1.18 1997/01/08 22:24:28 jik Exp $"; +static char XRNrcsid[] = "$Id: clientlib.c,v 1.19 1998/07/10 13:38:43 jik Exp $"; #endif /* #define DEBUG */ @@ -499,7 +499,6 @@ server); fputs(server_init_msg, stdout); return(-1); - break; default: printf("Unexpected response code from the %s news server.\n", diff -ruNP xrn-9.01/compose.c xrn-9.02/compose.c --- xrn-9.01/compose.c Wed May 13 21:29:15 1998 +++ xrn-9.02/compose.c Fri Sep 24 10:00:55 1999 @@ -1,5 +1,5 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: compose.c,v 1.122 1998/05/14 01:29:15 jik Exp $"; +static char XRNrcsid[] = "$Id: compose.c,v 1.126 1999/09/24 14:00:55 jik Exp $"; #endif /* @@ -95,6 +95,7 @@ #include "mesg_strings.h" #ifdef INN +#include #include #include #endif @@ -139,6 +140,7 @@ static void compose_buttons _ARGUMENTS((Widget, int)); static int check_quoted_text _ARGUMENTS((char *)); static char *insert_courtesy_tag _ARGUMENTS((char *)); +static Boolean IsValidAddressField _ARGUMENTS((CONST char *)); #ifdef GENERATE_EXTRA_FIELDS static char *gen_id _ARGUMENTS((void)); @@ -269,6 +271,7 @@ host: * Contents of the HIDDENHOST environment variable, if it's set, or + * Contents of the hiddenHost X resource, if it's set, or * INN "fromhost" configuration value, if using INN and it's set, or * Contents of the file HIDDEN_FILE, if it's defined and non-empty, or * The string RETURN_HOST, if it's defined, or @@ -282,6 +285,7 @@ * Contents of real_host host's domain: (only if host doesn't already have a period in it) + * Contents of the "domainName" X resource, if it's set, or * Contents of the DOMAIN environment variable, if it's set, or * INN "domain" configuration value, if using INN and it's set, or * Contents of the file DOMAIN_FILE, if it's defined and non-empty, or @@ -1399,14 +1403,41 @@ buffer2_size = 0; buildRealFrom(&Header, &buffer2, &buffer2_size, &buffer2_total_size); if (strcmp(buffer, buffer2)) { + char *addr, *addr_buf, *end, *nl; + + addr = strchr(buffer, ':') + 1; + addr_buf = addr = XtNewString(addr); + + /* Get rid of newlines */ + while ((nl = strchr(addr, '\n'))) + *nl = ' '; + + /* Strip whitespace in front */ + while (isspace((unsigned char) *addr)) + addr++; + + /* Strip whitespace at the end */ + for (end = strchr(addr, '\0') - 1; + end > addr && isspace((unsigned char) *end); + end--) + *end = '\0'; + + /* Now make sure its basic syntax is correct */ + if (! IsValidAddressField(addr)) { + XBell(XtDisplay(TopLevel), 0); + mesgPane(XRN_SERIOUS, 0, BAD_FROM_MSG, addr); + XtFree(addr_buf); + if (app_resources.editorCommand) + Call_Editor(True, False); + TextEnableRedisplay(ComposeText); + CLEANUP(); return; + } + #ifdef SENDMAIL_VERIFY if (app_resources.verifyFrom) { - char *verify_command, *addr, *addr_buf, *ptr, *ptr2; + char *verify_command, *ptr, *ptr2; int cmd_length; - addr = strchr(buffer, ':') + 1; - addr_buf = addr = XtNewString(addr); - while (isspace((unsigned char)*addr)) addr++; if ((ptr = strchr(addr, '\n'))) { @@ -1423,21 +1454,16 @@ verify_command = XtMalloc(cmd_length); (void) strcpy(verify_command, SENDMAIL_VERIFY); ptr = &verify_command[sizeof(SENDMAIL_VERIFY)-1]; - *ptr++ = ' '; - *ptr++ = '\''; + *ptr++ = ' '; *ptr++ = '\''; for (ptr2 = addr; *ptr2; ptr2++) { if (*ptr2 == '\'' || *ptr2 == '\\') { - *ptr++ = '\''; - *ptr++ = '\\'; - *ptr++ = *ptr2; - *ptr++ = '\''; + *ptr++ = '\''; *ptr++ = '\\'; *ptr++ = *ptr2; *ptr++ = '\''; } else { *ptr++ = *ptr2; } } - *ptr++ = '\''; - *ptr++ = '\0'; + *ptr++ = '\''; *ptr++ = '\0'; if (system(verify_command)) { XBell(XtDisplay(TopLevel), 0); @@ -1446,18 +1472,16 @@ if (app_resources.editorCommand) Call_Editor(True, False); TextEnableRedisplay(ComposeText); - CLEANUP(); - return; + CLEANUP(); return; } - - XtFree(addr_buf); } #endif /* SENDMAIL_VERIFY */ - *buffer = '\0'; - buffer_size = 0; - buildSender(&Header, &buffer, &buffer_size, &buffer2_size); - addField(buffer); + XtFree(addr_buf); + *buffer = '\0'; + buffer_size = 0; + buildSender(&Header, &buffer, &buffer_size, &buffer2_size); + addField(buffer); } } #endif /* ! INEWS */ @@ -3580,4 +3604,187 @@ XtFree(message); return(new_message); +} + +/* + Converts address fields as follows: + + From To + ---- -- + address address + stuff1
address + address (stuff2) address + + Makes sure that "address" contains '@', contains only valid + characters after the '@', and is quoted if it contains characters + before the '@' that need quoting. Makes sure that "stuff1" either + is quoted or doesn't contain a period or comma. Makes sure that + "stuff1" and "stuff2" don't contain parentheses or angle brackets. + Returns true if all this is OK or false otherwise. +*/ + +static Boolean check_address _ARGUMENTS((CONST char *)); +static Boolean check_stuff _ARGUMENTS((CONST char *, Boolean)); + +static Boolean IsValidAddressField(value_in) + CONST char *value_in; +{ + char *value, *value_buf, *address, *stuff, *ptr, *end; + Boolean retval = True; + + value_buf = value = XtNewString(value_in); + address = stuff = NULL; + + while ((ptr = strchr(value, '\n'))) + *ptr = ' '; + while (isspace((unsigned char) *value)) + value++; + for (end = strchr(value, '\0'), ptr = end - 1; + ptr > value && isspace((unsigned char) *ptr); + ptr--, end--) + *ptr = '\0'; + + /* Is it stuff1
? */ + ptr = end - 1; + if (ptr > value && *ptr == '>') { + *ptr-- = '\0'; + for (ptr = value; *ptr && *ptr != '<'; ptr++) + /* empty */; + if (*ptr != '<') { + retval = False; + goto finished; + } + address = ptr + 1; + stuff = value; + *ptr-- = '\0'; + while (ptr > stuff && isspace((unsigned char) *ptr)) + *ptr-- = '\0'; + if (! (retval = check_address(address))) + goto finished; + if (! (retval = check_stuff(stuff, True))) + goto finished; + } + /* Is it address (stuff2)? */ + else if (ptr > value && *ptr == ')') { + *ptr-- = '\0'; + while (ptr > value && *ptr != '(') + ptr--; + if (*ptr != '(') { + retval = False; + goto finished; + } + address = value; + stuff = ptr + 1; + *ptr-- = '\0'; + while (ptr > address && isspace((unsigned char) *ptr)) + *ptr-- = '\0'; + if (! (retval = check_address(address))) + goto finished; + if (! (retval = check_stuff(stuff, False))) + goto finished; + } + /* Otherwise, it's just an address */ + else { + retval = check_address(value); + } + + finished: + XtFree(value_buf); + return retval; +} + +/* + Make sure the address is in the form local-part@domain. If + local-part contains characters that need quoting, make sure that it + is surrounded by quotation marks. Returns True if the address is OK + or False otherwise. +*/ + +static Boolean check_address(address) + CONST char *address; +{ + static char special_chars[] = "()<>@,;:\\\"[] "; + Boolean in_quotes, in_quoted_pair, in_local_part, found_dot; + CONST char *ptr; + + in_quotes = in_quoted_pair = found_dot = False; + in_local_part = True; + + for (ptr = address; *ptr; ptr++) { + if (in_local_part) { + if (in_quoted_pair) { + in_quoted_pair = False; + continue; + } + if (*ptr == '\\') { + in_quoted_pair = True; + continue; + } + if (in_quotes) { + if (*ptr == '"') + in_quotes = False; + continue; + } + if (*ptr == '"') { + in_quotes = True; + continue; + } + if (*ptr == '@') { + if (ptr == address) /* No local part! */ + return False; + in_local_part = False; + continue; + } + } + if (strchr(special_chars, *ptr)) + return False; + if (in_local_part) + continue; + if (*ptr == '.') + found_dot++; + } + + if (found_dot) + return True; + + return False; +} + +/* + Make sure that "stuff" doesn't contain parentheses, angle + brackets, or internal quotation marks. Furthermore, if + "needs_quoting" is true, make sure that it is enclosed in quotation + marks if it contains periods or commas. +*/ + +static Boolean check_stuff( + _ANSIDECL(CONST char *, stuff), + _ANSIDECL(Boolean, needs_quoting) + ) + _KNRDECL(CONST char *, stuff) + _KNRDECL(Boolean, needs_quoting) +{ + static char specials[] = "()<>\""; + static char quoted_specials[] = ".,"; + + CONST char *ptr, *end; + Boolean is_quoted = False; + + end = strchr(stuff, '\0'); + + if (*stuff == '"') { + if (*--end != '"') + return False; + stuff++; + is_quoted = True; + } + + for (ptr = stuff; ptr < end; ptr++) { + if (strchr(specials, *ptr)) + return False; + if (needs_quoting && !is_quoted && strchr(quoted_specials, *ptr)) + return False; + } + + return True; } diff -ruNP xrn-9.01/config.h xrn-9.02/config.h --- xrn-9.01/config.h Sun Mar 22 22:21:34 1998 +++ xrn-9.02/config.h Wed Sep 1 21:11:21 1999 @@ -2,7 +2,7 @@ #define CONFIG_H /* - * $Id: config.h,v 1.81 1998/03/23 01:13:06 jik Exp $ + * $Id: config.h,v 1.87 1999/09/02 01:11:20 jik Exp $ */ /* @@ -34,10 +34,6 @@ * config.h: configurable defaults */ -#ifdef OV_CAMBRIDGE -#define CONFIG_H_IS_OK -#endif - #ifndef CONFIG_H_IS_OK #error "You must edit config.h appropriately for your site!" #endif @@ -307,7 +303,7 @@ /* * Prefix for each line included from an article */ -#define INCLUDEPREFIX "|> " +#define INCLUDEPREFIX ">" /* * if there are more than this many unread articles in the next @@ -534,7 +530,8 @@ BSD_BFUNCS definitions in utils.h, then try undefining BSD_BFUNCS and defining NO_MEMMOVE instead. */ -#if defined(sequent) || !(defined(SYSV) || defined(sun)) +#if defined(sequent) || !(defined(SYSV) || defined(sun) || defined(ultrix) || \ + defined(linux)) # define BSD_BFUNCS #else # if defined(sun) && !defined(SOLARIS) @@ -570,7 +567,8 @@ * strtok, please let me know. - jik 10/23/94 */ #if defined(sequent) || (!defined(SYSV) && !defined(_ANSI_C_SOURCE) && \ - !(defined(sparc) && defined(sun) && defined(unix))) + !(defined(sparc) && defined(sun) && defined(unix)) && \ + !defined(linux)) #define NEED_STRTOK #endif @@ -581,7 +579,7 @@ * some cases noticeably. Our version is faster, so we use it * instead. */ -#if !defined(_ANSI_C_SOURCE) || \ +#if (!defined(_ANSI_C_SOURCE) && !defined(linux)) || \ (defined(sparc) && defined(sun) && defined(unix) && !defined(SOLARIS)) #define NEED_STRSTR #endif @@ -596,19 +594,6 @@ */ #if defined(SCO) #define NO_FCHMOD -#endif - -/* - * Configuration that the XRN maintainer uses. There's no point in - * touching this. - */ - -#ifdef OV_CAMBRIDGE -#define DOMAIN_NAME ".cam.ov.com" -#define RETURN_HOST "cam.ov.com" -#define SENDER_HOST "cam.ov.com" -#define ORG_NAME "OpenVision Technologies, Inc." -#define SERVER_FILE "/tools/share/news/server" #endif #endif /* CONFIG_H */ diff -ruNP xrn-9.01/dialogs.c xrn-9.02/dialogs.c --- xrn-9.01/dialogs.c Thu Feb 26 13:43:17 1998 +++ xrn-9.02/dialogs.c Sun Jul 5 10:39:13 1998 @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: dialogs.c,v 1.22 1998/02/26 18:43:16 jik Exp $"; +static char XRNrcsid[] = "$Id: dialogs.c,v 1.23 1998/07/05 14:39:13 jik Exp $"; /* Modified 2/20/92 dbrooks@osf.org to clean up dialog layout */ #endif @@ -328,8 +328,10 @@ Widget dialog = XtParent(XtParent(widget)); password_result = (int) client_data; - if (password_result == XRN_CB_CONTINUE) - dialog_password = XtNewString(GetDialogValue(dialog)); + if (password_result == XRN_CB_CONTINUE) { + dialog_password = GetDialogValue(dialog); + dialog_password = XtNewString(dialog_password); + } PopDownDialog(dialog); return; } diff -ruNP xrn-9.01/getdate.y xrn-9.02/getdate.y --- xrn-9.01/getdate.y Tue May 12 12:54:13 1998 +++ xrn-9.02/getdate.y Wed Jun 17 07:21:01 1998 @@ -573,11 +573,11 @@ if (Year < 0) Year = -Year; - if (Year < 100) + if (Year < 1000) Year += 1900; DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0) ? 29 : 28; - if (Year < EPOCH || Year > 1999 + if (Year < EPOCH || Year > 2999 || Month < 1 || Month > 12 /* Lint fluff: "conversion from long may lose accuracy" */ || Day < 1 || Day > DaysInMonth[(int)--Month]) diff -ruNP xrn-9.01/internals.c xrn-9.02/internals.c --- xrn-9.01/internals.c Tue May 12 13:00:49 1998 +++ xrn-9.02/internals.c Tue Jan 5 20:50:33 1999 @@ -1,5 +1,5 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: internals.c,v 1.222 1998/05/12 17:00:24 jik Exp $"; +static char XRNrcsid[] = "$Id: internals.c,v 1.230 1999/01/06 01:50:32 jik Exp $"; #endif /* @@ -1179,10 +1179,11 @@ { struct article *art; art_num i, start, last; - char *subject, *from, *newsgroups, *date, *id, *references, *xref; - int scount = 0, kcount = 0, mcount = 0; + char *subject, *from, *newsgroups, *date, *id, *references, *xref, *approved; + int scount = 0, kcount = 0, mcount = 0, tcount = 0; int mesg_name; - kill_entry *entry = 0; + kill_entry *entry; + kill_file_iter_handle handle = 0; kill_file *kf; int cur_mode = KILL_LOCAL; @@ -1217,10 +1218,11 @@ kf->thru = last; while (1) { - if (! (entry = kill_file_iter(newsgroup, cur_mode, entry))) { + if (! (entry = kill_file_iter(newsgroup, cur_mode, &handle))) { if (cur_mode != KILL_LOCAL) break; cur_mode = KILL_GLOBAL; + handle = 0; continue; } @@ -1236,7 +1238,8 @@ /* short cut */ if (IS_KILLED(art) || IS_UNAVAIL(art) || - ((entry->entry.action_flags & KILL_JUNK) && IS_READ(art)) || + ((entry->entry.action_flags & (KILL_JUNK|KILL_SUBTHREAD|KILL_THREAD)) + && IS_READ(art)) || ((entry->entry.action_flags & KILL_MARK) && IS_UNREAD(art))) continue; @@ -1255,6 +1258,7 @@ CHECK_FIELD(KILL_ID, id); CHECK_FIELD(KILL_REFERENCES, references); CHECK_FIELD(KILL_XREF, xref); + CHECK_FIELD(KILL_APPROVED, approved); if (field_count) { struct article copy; @@ -1275,10 +1279,26 @@ if (KILL_MATCH(subject) || KILL_MATCH(from) || KILL_MATCH(date) || KILL_MATCH(newsgroups) || KILL_MATCH(id) || KILL_MATCH(references) || - KILL_MATCH(xref)) { + KILL_MATCH(xref) || KILL_MATCH(approved)) { kill_update_last_used(kf, entry); switch (entry->entry.action_flags) { + case KILL_SUBTHREAD: + case KILL_THREAD: { + char *id = 0, *quoted_id; + + if (entry->entry.action_flags == KILL_THREAD) + id = getFirstReference(art->references); + if (! id) + id = art->id; + + quoted_id = stringToRegexp(id, MAX_KILL_PATTERN_VALUE_LENGTH); + add_kill_entry(newsgroup, cur_mode, "References", quoted_id); + if (index(app_resources.verboseKill, 't')) + mesgPane(XRN_INFO, mesg_name, KILL_THREAD_MSG, art->subject); + tcount++; + /* fall through to kill the article itself */ + } case KILL_JUNK: SET_READ(©); if (index(app_resources.verboseKill, 'j')) { @@ -1340,6 +1360,7 @@ printcount(kcount, 'j', COUNT_KILLED_MSG); printcount(mcount, 'm', COUNT_UNREAD_MSG); printcount(scount, 's', COUNT_SAVED_MSG); + printcount(tcount, 't', COUNT_THREAD_MSG); #undef printcount @@ -1370,7 +1391,7 @@ static struct newsgroup *last_group = 0; char dummy[LABEL_SIZE]; Boolean finished = True; - unsigned char fetched = newsgroup->fetch; + fetch_flag_t fetched = newsgroup->fetch; #ifdef DEBUG fprintf(stderr, "checkKillFiles(%s, %d)\n", newsgroup->name, prefetching); @@ -1602,9 +1623,10 @@ for (i = first; (i <= last) && (! stage || (done_count < chunk_size)); i++) { - struct article *art = artStructGet(newsgroup, i, False), copy = *art; + struct article *art = artStructGet(newsgroup, i, False), copy; char *references, *ptr; art_num parent; + copy = *art; if (copy.parent || !THREAD_IT(©)) continue; @@ -1812,6 +1834,12 @@ unread_only, (stage && ! FinishingPrefetch) ? &chunk_size : 0); + if ((newsgroup->fetch & FETCH_APPROVED) && + (! stage || *stage == PREFETCH_APPROVED_STAGE)) + finished = getapprovedlist(newsgroup, first, last, + unread_only, + (stage && ! FinishingPrefetch) + ? &chunk_size : 0); if ((newsgroup->fetch & FETCH_REFS) && (! stage || *stage == PREFETCH_REFS_STAGE)) finished = getreflist(newsgroup, first, last, @@ -1941,7 +1969,7 @@ if (! stage || *stage == PREFETCH_KILL_STAGE) { if ((app_resources.killFiles == TRUE) && kill_files) { - unsigned char fetched = newsgroup->fetch; + fetch_flag_t fetched = newsgroup->fetch; finished = checkKillFiles(newsgroup, (stage && ! FinishingPrefetch) @@ -3968,7 +3996,21 @@ } if (newsgroup->current > newsgroup->last) + if (flags & ENTER_UNREAD) ret = XRN_NOUNREAD; + else + /* + In an ideal world, this case would never happen, because + a group's first and last article numbers as returned by + the server would tell EMPTY_GROUP that the group is + empty. Unfortunately, some news servers don't return + useful first and last article number information, e.g., + they'll return a range indicating that there are + articles in the group when in fact there are not. So + we need to be careful to detect that and deal with it + appropriately. + */ + ret = XRN_NOMORE; else { struct article *art = artStructGet(newsgroup, newsgroup->current, False); @@ -4115,4 +4157,33 @@ return -2; return 0; +} + +char *getFirstReference(references) + char *references; +{ + static char *ref_buf = NULL; + static int buf_size = 0; + char *lbrace, *rbrace; + + if (! (references && *references)) + return NULL; + + if (! (lbrace = strchr(references, '<'))) + return NULL; + + if (! (rbrace = strchr(lbrace, '>'))) + return NULL; + + rbrace++; + + if (rbrace - lbrace + 1 > buf_size) { + buf_size = rbrace - lbrace + 1; + ref_buf = XtRealloc(ref_buf, buf_size); + } + + strncpy(ref_buf, lbrace, rbrace - lbrace); + ref_buf[rbrace - lbrace] = '\0'; + + return ref_buf; } diff -ruNP xrn-9.01/internals.h xrn-9.02/internals.h --- xrn-9.01/internals.h Fri Jul 18 08:57:29 1997 +++ xrn-9.02/internals.h Tue Jan 5 20:50:15 1999 @@ -2,7 +2,7 @@ #define INTERNALS_H /* - * $Id: internals.h,v 1.48 1997/07/18 12:57:29 jik Exp $ + * $Id: internals.h,v 1.51 1999/01/06 01:50:15 jik Exp $ */ /* @@ -220,9 +220,10 @@ #define PREFETCH_IDS_STAGE 8 #define PREFETCH_REFS_STAGE 9 #define PREFETCH_XREF_STAGE 10 -#define PREFETCH_LAST_HEADERS_STAGE PREFETCH_XREF_STAGE -#define PREFETCH_KILL_STAGE 11 -#define PREFETCH_THREAD_STAGE 12 +#define PREFETCH_APPROVED_STAGE 11 +#define PREFETCH_LAST_HEADERS_STAGE PREFETCH_APPROVED_STAGE +#define PREFETCH_KILL_STAGE 12 +#define PREFETCH_THREAD_STAGE 13 #define PREFETCH_LAST_OPTIONAL_STAGE PREFETCH_THREAD_STAGE #define PREFETCH_LAST_STAGE PREFETCH_THREAD_STAGE @@ -237,16 +238,25 @@ #define PREFETCH_FIELD_BIT(stage) (1<<(stage-PREFETCH_START_OPTIONAL_STAGE)) +/* If there end up being more than 8 of these, then the typedef of + fetch_flag_t in news.h needs to change. */ #define FETCH_NEWSGROUPS PREFETCH_FIELD_BIT(PREFETCH_NEWSGROUPS_STAGE) #define FETCH_DATES PREFETCH_FIELD_BIT(PREFETCH_DATE_STAGE) #define FETCH_IDS PREFETCH_FIELD_BIT(PREFETCH_IDS_STAGE) #define FETCH_REFS PREFETCH_FIELD_BIT(PREFETCH_REFS_STAGE) #define FETCH_XREF PREFETCH_FIELD_BIT(PREFETCH_XREF_STAGE) +#define FETCH_APPROVED PREFETCH_FIELD_BIT(PREFETCH_APPROVED_STAGE) #define FETCH_THREADS PREFETCH_FIELD_BIT(PREFETCH_THREAD_STAGE) /* Given an article's message ID, get its number in a newsgroup. Returns the article number on success, 0 on failure, or -1 on abort. */ extern art_num getArticleNumberFromIdXref _ARGUMENTS((struct newsgroup *, char *)); + +/* Get the first valid message ID in a list of message IDs (i.e., a + references line). The returned memory is static, should not be + tampered with, and is only valid until the next call to the + function. */ +char *getFirstReference _ARGUMENTS((char *)); #endif /* INTERNALS_H */ diff -ruNP xrn-9.01/killfile.c xrn-9.02/killfile.c --- xrn-9.01/killfile.c Tue May 12 12:54:13 1998 +++ xrn-9.02/killfile.c Tue Jan 5 19:55:08 1999 @@ -26,15 +26,15 @@ #define DEF_CHECK_FLAGS (KILL_SUBJECT|KILL_AUTHOR) #define ALL_CHECK_FLAGS (KILL_SUBJECT|KILL_AUTHOR|\ KILL_NEWSGROUPS|KILL_DATE|\ - KILL_ID|KILL_REFERENCES) + KILL_ID|KILL_REFERENCES|KILL_APPROVED) static void free_entry_contents _ARGUMENTS((kill_entry *)); -static char field_to_check_flag _ARGUMENTS((char *, int)); +static kill_check_flag_t field_to_check_flag _ARGUMENTS((char *, int)); static Boolean entry_expired _ARGUMENTS((kill_entry *, time_t)); static void write_kf _ARGUMENTS((kill_file *)); static kill_file *read_kf _ARGUMENTS((char *file_name, char *reference, - unsigned char *fetch_flags)); + fetch_flag_t *fetch_flags)); /* @@ -68,7 +68,7 @@ static void parse_kill_entry _ARGUMENTS((char *, char *, kill_file *, kill_entry *, - unsigned char *, int)); + fetch_flag_t *, int)); /* Parse a KILL-file entry. If there's a parse error, this routine @@ -107,7 +107,7 @@ char *in_str; kill_file *file; kill_entry *entry; - unsigned char *fetch_flags; + fetch_flag_t *fetch_flags; int mesg_name; { kill_entry my_entry; @@ -316,6 +316,12 @@ case 's': my_entry.entry.action_flags = KILL_SAVE; break; + case 't': + my_entry.entry.action_flags = KILL_SUBTHREAD; + break; + case 'T': + my_entry.entry.action_flags = KILL_THREAD; + break; default: mesgPane(XRN_SERIOUS, mesg_name, MALFORMED_KILL_ENTRY_MSG, str, file_name, ERROR_REGEX_UNKNOWN_COMMAND_MSG); @@ -360,6 +366,13 @@ *fetch_flags |= FETCH_REFS; if (my_entry.entry.check_flags & KILL_XREF) *fetch_flags |= FETCH_XREF; + if (my_entry.entry.check_flags & KILL_APPROVED) + *fetch_flags |= FETCH_APPROVED; + + if (my_entry.entry.action_flags == KILL_SUBTHREAD) + *fetch_flags |= FETCH_IDS; + if (my_entry.entry.action_flags == KILL_THREAD) + *fetch_flags |= FETCH_IDS & FETCH_REFS; my_entry.type = KILL_ENTRY; @@ -375,7 +388,7 @@ struct kftab_entry { char ref_count; - unsigned char fetch_flags; + fetch_flag_t fetch_flags; kill_file *kill_file; }; @@ -470,6 +483,12 @@ case KILL_SAVE: *ptr++ = 's'; break; + case KILL_SUBTHREAD: + *ptr++ = 't'; + break; + case KILL_THREAD: + *ptr++ = 'T'; + break; default: assert(0); } @@ -483,7 +502,7 @@ static kill_file *GlobalKillFile = 0; -static unsigned char GlobalFetchFlags = 0; +static fetch_flag_t GlobalFetchFlags = 0; void read_global_kill_file(newsgroup) @@ -513,7 +532,7 @@ static kill_file *read_kf(file_name, reference, fetch_flags) char *file_name; char *reference; - unsigned char *fetch_flags; + fetch_flag_t *fetch_flags; { int entries_size; FILE *fp; @@ -614,24 +633,26 @@ return kf; } -static kill_entry *kf_iter _ARGUMENTS((kill_file *, kill_entry *, +static kill_entry *kf_iter _ARGUMENTS((kill_file *, kill_file_iter_handle *, Boolean)); static kill_entry *kf_iter( - _ANSIDECL(kill_file *, kf), - _ANSIDECL(kill_entry *, last_entry), - _ANSIDECL(Boolean, expand_includes) + _ANSIDECL(kill_file *, kf), + _ANSIDECL(kill_file_iter_handle *, handle_p), + _ANSIDECL(Boolean, expand_includes) ) - _KNRDECL(kill_file *, kf) - _KNRDECL(kill_entry *, last_entry) - _KNRDECL(Boolean, expand_includes) + _KNRDECL(kill_file *, kf) + _KNRDECL(kill_file_iter_handle *, handle_p) + _KNRDECL(Boolean, expand_includes) { kill_entry *sub_entry = 0; + int handle = (int) *handle_p; + kill_entry *this_entry; assert(kf); - if (! last_entry) { - last_entry = kf->entries; + if (! handle_p) { + handle = 1; if (expand_includes) kf->flags |= KF_SEEN; } @@ -639,47 +660,54 @@ assert(expand_includes); assert(kf->cur_entry); - sub_entry = kf_iter(kf->cur_sub_kf, last_entry, expand_includes); + sub_entry = kf_iter(kf->cur_sub_kf, handle_p, expand_includes); if (sub_entry) return sub_entry; kf->cur_sub_kf = 0; - last_entry = kf->cur_entry; - last_entry++; + handle = kf->cur_entry; + handle++; } else { - last_entry++; + handle++; } - if (last_entry - kf->entries == kf->count) + if (handle > kf->count) return 0; + this_entry = &kf->entries[handle-1]; + #if !defined(POSIX_REGEX) && !defined(SYSV_REGEX) - if (last_entry->type == KILL_ENTRY) - (void) re_comp(last_entry->entry.reStruct); + if (this_entry->type == KILL_ENTRY) + (void) re_comp(this_entry->entry.reStruct); #endif - if ((last_entry->type == KILL_INCLUDE) && expand_includes) { - if (! (last_entry->include.kf->flags & KF_SEEN)) { - sub_entry = kf_iter(last_entry->include.kf, 0, expand_includes); + if ((this_entry->type == KILL_INCLUDE) && expand_includes) { + if (! (this_entry->include.kf->flags & KF_SEEN)) { + kill_file_iter_handle sub_handle = 0; + + sub_entry = kf_iter(this_entry->include.kf, &sub_handle, expand_includes); if (sub_entry) { - kf->cur_entry = last_entry; - kf->cur_sub_kf = last_entry->include.kf; + kf->cur_entry = handle; + kf->cur_sub_kf = this_entry->include.kf; + *handle_p = sub_handle; return sub_entry; } } - return kf_iter(kf, last_entry, expand_includes); + *handle_p = (kill_file_iter_handle) handle; + return kf_iter(kf, handle_p, expand_includes); } - return last_entry; + *handle_p = (kill_file_iter_handle) handle; + return this_entry; } -kill_entry *kill_file_iter(newsgroup, mode, last_entry) +kill_entry *kill_file_iter(newsgroup, mode, handle) struct newsgroup *newsgroup; int mode; - kill_entry *last_entry; + kill_file_iter_handle *handle; { kill_file *kf; @@ -690,7 +718,7 @@ clear_seen(); - return kf_iter(kf, last_entry, True); + return kf_iter(kf, handle, True); } #define CHECK_WRITE(cmd) if (! (cmd)) { \ @@ -707,7 +735,8 @@ char *temp_file = 0; FILE *fp; char buf[MAX_KILL_ENTRY_LENGTH]; - kill_entry *entry = 0; + kill_entry *entry; + kill_file_iter_handle handle = 0; time_t now = time(0); int mesg_name = newMesgPaneName(); @@ -745,7 +774,7 @@ CHECK_WRITE(fprintf(fp, "THRU %ld\n", kf->thru) != EOF); } - while ((entry = kf_iter(kf, entry, False))) { + while ((entry = kf_iter(kf, &handle, False))) { if (entry_expired(entry, now)) continue; unparse_kill_entry(entry, buf); @@ -769,7 +798,8 @@ XtFree(temp_file); } - while ((entry = kf_iter(kf, entry, False))) + handle = 0; + while ((entry = kf_iter(kf, &handle, False))) free_entry_contents(entry); XtFree((char *)kf->entries); XtFree((char *)kf); @@ -844,7 +874,7 @@ char *file; kill_entry my_entry; int mesg_name = newMesgPaneName(); - unsigned char *fetch_ptr; + fetch_flag_t *fetch_ptr; struct stat statbuf; if (mode == KILL_LOCAL) { @@ -924,7 +954,7 @@ return(flag); \ } -static char field_to_check_flag(field_name, field_length) +static kill_check_flag_t field_to_check_flag(field_name, field_length) char *field_name; int field_length; { @@ -935,6 +965,7 @@ CHECK_FIELD("Message-ID", KILL_ID); CHECK_FIELD("References", KILL_REFERENCES); CHECK_FIELD("Xref", KILL_XREF); + CHECK_FIELD("Approved", KILL_APPROVED); return 0; } diff -ruNP xrn-9.01/killfile.h xrn-9.02/killfile.h --- xrn-9.01/killfile.h Sun Jul 13 21:22:59 1997 +++ xrn-9.02/killfile.h Tue Jan 5 19:55:26 1999 @@ -29,10 +29,15 @@ #define KILL_ID (1<<4) #define KILL_REFERENCES (1<<5) #define KILL_XREF (1<<6) +#define KILL_APPROVED (1<<7) -#define KILL_JUNK (1<<0) -#define KILL_MARK (1<<1) -#define KILL_SAVE (1<<2) +typedef unsigned int kill_check_flag_t; + +#define KILL_JUNK (1<<0) +#define KILL_MARK (1<<1) +#define KILL_SAVE (1<<2) +#define KILL_SUBTHREAD (1<<3) +#define KILL_THREAD (1<<4) typedef union _kill_entry { char type; @@ -49,7 +54,7 @@ #else char *reStruct; #endif /* POSIX_REGEX */ - char check_flags; + kill_check_flag_t check_flags; char action_flags; int timeout; time_t last_used; @@ -74,17 +79,19 @@ int count; kill_entry *entries; struct _kill_file *cur_sub_kf; - kill_entry *cur_entry; + int cur_entry; char flags; } kill_file; +typedef void *kill_file_iter_handle; + #define KF_SEEN (1<<0) #define KF_CHANGED (1<<1) void read_global_kill_file _ARGUMENTS((struct newsgroup *)); void read_local_kill_file _ARGUMENTS((struct newsgroup *)); kill_entry *kill_file_iter _ARGUMENTS((struct newsgroup *, int mode, - kill_entry *)); + kill_file_iter_handle *handle)); void write_kill_file _ARGUMENTS((struct newsgroup *, int mode)); Boolean has_kill_files _ARGUMENTS((struct newsgroup *)); void add_kill_entry _ARGUMENTS((struct newsgroup *newsgroup, int mode, diff -ruNP xrn-9.01/mesg_strings.c xrn-9.02/mesg_strings.c --- xrn-9.01/mesg_strings.c Mon Mar 23 08:21:32 1998 +++ xrn-9.02/mesg_strings.c Wed Dec 30 09:25:53 1998 @@ -1,5 +1,5 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: mesg_strings.c,v 1.88 1998/03/23 13:21:31 jik Exp $"; +static char XRNrcsid[] = "$Id: mesg_strings.c,v 1.91 1998/12/30 14:25:53 jik Exp $"; #endif /* @@ -713,12 +713,16 @@ "marked unread - %s", /* subject */ /* < KILL_SAVED > */ "saved - %s", /* subject */ +/* < KILL_THREAD > */ + "killed thread - %s", /* subject */ /* < COUNT_KILLED > */ "killed %d article%s in %s", /* count, "" or NOT_ONE_STRING , newsgroup */ /* < COUNT_UNREAD > */ "marked %d article%s unread in %s", /* count, "" or NOT_ONE_STRING , newsgroup */ /* < COUNT_SAVED > */ "saved %d article%s in %s", /* count, "" or NOT_ONE_STRING , newsgroup */ +/* < COUNT_THREAD > */ + "killed %d thread%s in %s", /* count, "" or NOT_ONE_STRING, newsgroup */ /* < ERROR_CORNERED > */ "XRN error in `cornered': expecting nglist to be valid\n", /* < ERROR_OUT_OF_MEM > */ @@ -1228,12 +1232,16 @@ "marqué non lu - %s", /* subject */ /* < KILL_SAVED > */ "sauvé - %s", /* subject */ +/* < KILL_THREAD > */ + "killed thread - %s", /* subject */ /* < COUNT_KILLED > */ "%d article%s tués dans %s", /* count, "" or NOT_ONE_STRING , newsgroup */ /* < COUNT_UNREAD > */ "%d article%s marqués non lus dans %s", /* count, "" or NOT_ONE_STRING , newsgroup */ /* < COUNT_SAVED > */ "%d article%s sauvés dans %s", /* count, "" or NOT_ONE_STRING , newsgroup */ +/* < COUNT_THREAD > */ + "killed %d thread%s in %s", /* count, "" or NOT_ONE_STRING, newsgroup */ /* < ERROR_CORNERED > */ "Erreur XRN dans `cornered' : nglist aurait dû être valide\n", /* < ERROR_OUT_OF_MEM > */ @@ -1762,12 +1770,16 @@ "als ungelesen markiert - %s", /* subject */ /* < KILL_SAVED > */ "gesichert - %s", /* subject */ +/* < KILL_THREAD > */ + "Serie ausgeblendet - %s", /* subject */ /* < COUNT_KILLED > */ "%d Artikel%s in %s ausgeblendet", /* count, "" or NOT_ONE_STRING , newsgroup */ /* < COUNT_UNREAD > */ "%d Artikel%s in %s als ungelesen markiert", /* count, "" or NOT_ONE_STRING , newsgroup */ /* < COUNT_SAVED > */ "%d Artikel%s in %s abgespeichert", /* count, "" or NOT_ONE_STRING , newsgroup */ +/* < COUNT_THREAD > */ + "killed %d thread%s in %s", /* count, "" or NOT_ONE_STRING, newsgroup */ /* < ERROR_CORNERED > */ "XRN Fehler in `cornered': erwarte g\374ltige nglist\n", /* < ERROR_OUT_OF_MEM > */ diff -ruNP xrn-9.01/news.h xrn-9.02/news.h --- xrn-9.01/news.h Tue Jul 1 10:27:46 1997 +++ xrn-9.02/news.h Tue Jan 5 20:50:12 1999 @@ -2,7 +2,7 @@ #define NEWS_H /* - * $Id: news.h,v 1.28 1997/07/01 14:26:27 jik Exp $ + * $Id: news.h,v 1.32 1999/01/06 01:50:12 jik Exp $ */ /* @@ -42,6 +42,7 @@ typedef long art_num; /* easy way to pick out variables refering to articles */ typedef unsigned short ng_num; /* easy way to pick out newsgroup variables */ +typedef unsigned char fetch_flag_t; extern avl_tree *NewsGroupTable; extern int ActiveGroupsCount; @@ -60,6 +61,7 @@ char *id; /* message ID (maybe) */ char *references; /* references (maybe) */ char *xref; /* xref (maybe) */ + char *approved; /* Approved (maybe) */ art_num parent; /* parent article, for threading */ art_num *children; /* child articles, for threading */ #ifdef ARTSTRUCT_C @@ -82,7 +84,7 @@ art_num current; /* current article number */ struct list *nglist; /* newsgroup entry for unsubscribed groups */ unsigned char from_cache; /* is this entry from the active file cache? */ - unsigned char fetch; /* what should we fetch? */ + fetch_flag_t fetch; /* what should we fetch? */ hash_table_object thread_table; void *kill_file; #ifdef ARTSTRUCT_C @@ -169,6 +171,7 @@ _CLEAR_XREF((art),(free)); \ _CLEAR_PARENT((art),(free)); \ _CLEAR_CHILDREN((art),(free)); \ + _CLEAR_APPROVED((art),(free)); \ #define _CLEAR_FILE(art,free) \ if ((free) && (art)->file) { \ @@ -239,6 +242,12 @@ } \ (art)->xref = 0; +#define _CLEAR_APPROVED(art,free) \ + if ((free) && (art)->xref) { \ + FREE((art)->approved); \ + } \ + (art)->approved = 0; + #define _CLEAR_PARENT(art,free) \ (art)->parent = 0; @@ -262,6 +271,7 @@ #define CLEAR_ID(art) _CLEAR_ID((art),1) #define CLEAR_REFS(art) _CLEAR_REFS((art),1) #define CLEAR_XREF(art) _CLEAR_XREF((art),1) +#define CLEAR_APPROVED(art) _CLEAR_APPROVED((art),1) #define CLEAR_PARENT(art) _CLEAR_PARENT((art),1) #define CLEAR_CHILDREN(art) _CLEAR_CHILDREN((art),1) diff -ruNP xrn-9.01/patchlevel.h xrn-9.02/patchlevel.h --- xrn-9.01/patchlevel.h Mon May 25 11:12:43 1998 +++ xrn-9.02/patchlevel.h Fri Sep 24 10:23:42 1999 @@ -1,5 +1,5 @@ #ifdef MOTIF -#define XRN_VERSION "9.01 (Motif)" +#define XRN_VERSION "9.02 (Motif)" #else -#define XRN_VERSION "9.01" +#define XRN_VERSION "9.02" #endif diff -ruNP xrn-9.01/refile.c xrn-9.02/refile.c --- xrn-9.01/refile.c Fri Jul 4 13:30:10 1997 +++ xrn-9.02/refile.c Mon Aug 30 08:13:14 1999 @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: refile.c,v 1.15 1997/07/04 17:30:10 jik Exp $"; +static char XRNrcsid[] = "$Id: refile.c,v 1.16 1999/08/30 12:13:14 jik Exp $"; #endif /* @@ -56,8 +56,6 @@ #include "error_hnds.h" #include "mesg_strings.h" #include "refile.h" - -extern char *strpbrk(); #ifndef S_ISDIR #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) diff -ruNP xrn-9.01/resources.c xrn-9.02/resources.c --- xrn-9.01/resources.c Sun Mar 22 22:16:55 1998 +++ xrn-9.02/resources.c Sun Jul 5 11:08:36 1998 @@ -1,5 +1,5 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: resources.c,v 1.62 1998/03/23 03:16:54 jik Exp $"; +static char XRNrcsid[] = "$Id: resources.c,v 1.63 1998/07/05 15:08:35 jik Exp $"; #endif /* @@ -72,6 +72,8 @@ #define XtCArtButtonList "ArtButtonList" #define XtNartSpecButtonList "artSpecButtonList" #define XtCArtSpecButtonList "ArtSpecButtonList" +#define XtNauthenticateOnConnect "authenticateOnConnect" +#define XtCAuthenticateOnConnect "AuthenticateOnConnect" #define XtNauthenticator "authenticator" #define XtCAuthenticator "Authenticator" #define XtNauthenticatorCommand "authenticatorCommand" @@ -360,6 +362,8 @@ XtOffset(app_res,artButtonList), XtRString, (XtPointer) NULL}, {XtNartSpecButtonList, XtCArtSpecButtonList, XtRString, sizeof(char *), XtOffset(app_res,artSpecButtonList), XtRString, (XtPointer) NULL}, + {XtNauthenticateOnConnect, XtCAuthenticateOnConnect, XtRBoolean, sizeof(Boolean), + XtOffset(app_res,authenticateOnConnect), XtRBoolean, (XtPointer) &defaultFalse}, {XtNauthenticator, XtCAuthenticator, XtRString, sizeof(char *), XtOffset(app_res,authenticator), XtRString, (XtPointer) NULL}, {XtNauthenticatorCommand, XtCAuthenticatorCommand, XtRString, sizeof(char *), diff -ruNP xrn-9.01/resources.h xrn-9.02/resources.h --- xrn-9.01/resources.h Sun Mar 22 22:17:04 1998 +++ xrn-9.02/resources.h Sun Jul 5 11:08:33 1998 @@ -2,7 +2,7 @@ #define RESOURCES_H /* - * $Id: resources.h,v 1.38 1998/03/23 03:17:04 jik Exp $ + * $Id: resources.h,v 1.39 1998/07/05 15:08:33 jik Exp $ */ /* @@ -130,6 +130,7 @@ char *ignoreNewsgroups; char *validNewsgroups; char *domainName; + Boolean authenticateOnConnect; char *authenticatorCommand; char *authenticator; Boolean rescanOnEnter, stayInArticleMode, subjectScrollBack, discardOld; diff -ruNP xrn-9.01/server.c xrn-9.02/server.c --- xrn-9.01/server.c Tue May 12 13:00:50 1998 +++ xrn-9.02/server.c Sun Jan 3 11:02:29 1999 @@ -1,6 +1,6 @@ #if !defined(lint) && !defined(SABER) && !defined(GCC_WALL) -static char XRNrcsid[] = "$Id: server.c,v 1.150 1998/05/12 17:00:24 jik Exp $"; +static char XRNrcsid[] = "$Id: server.c,v 1.153 1999/01/03 16:02:26 jik Exp $"; #endif /* @@ -905,8 +905,9 @@ curtime = gmtime(&clock); assert(curtime); (void) sprintf(date_buf, "%02d%02d%02d %02d%02d%02d GMT", - curtime->tm_year, curtime->tm_mon + 1, curtime->tm_mday, - curtime->tm_hour, curtime->tm_min, curtime->tm_sec); + curtime->tm_year % 100, curtime->tm_mon + 1, + curtime->tm_mday, curtime->tm_hour, curtime->tm_min, + curtime->tm_sec); } return date_buf; @@ -1416,7 +1417,8 @@ PostingAllowed = False; else if (response >= 0) response = handle_server_response(response, server); - if (response >= 0) + if ((response >= 0) && + !(app_resources.authenticateOnConnect && authenticate())) break; stop_server(); (void) sprintf(buf, FAILED_CONNECT_MSG, server); @@ -1706,6 +1708,28 @@ return getlist(newsgroup, artfirst, artlast, unreadonly, max, "xref", offset, 0, 0, False); +} + +Boolean getapprovedlist( + _ANSIDECL(struct newsgroup *, newsgroup), + _ANSIDECL(art_num, artfirst), + _ANSIDECL(art_num, artlast), + _ANSIDECL(Boolean, unreadonly), + _ANSIDECL(int *, max) + ) + _KNRDECL(struct newsgroup *, newsgroup) + _KNRDECL(art_num, artfirst) + _KNRDECL(art_num, artlast) + _KNRDECL(Boolean, unreadonly) + _KNRDECL(int *, max) +{ + struct article foo; + unsigned offset; + + offset = (char *)&foo.approved - (char *)&foo; + + return getlist(newsgroup, artfirst, artlast, unreadonly, max, + "approved", offset, 0, 0, False); } Boolean getdatelist( diff -ruNP xrn-9.01/server.h xrn-9.02/server.h --- xrn-9.01/server.h Tue Feb 10 22:43:23 1998 +++ xrn-9.02/server.h Tue Jan 5 20:50:22 1999 @@ -2,7 +2,7 @@ #define SERVER_H /* - * $Id: server.h,v 1.32 1998/02/11 03:43:23 jik Exp $ + * $Id: server.h,v 1.33 1999/01/03 16:02:26 jik Exp $ */ /* @@ -96,6 +96,8 @@ Boolean, int *)); extern Boolean getxreflist _ARGUMENTS((struct newsgroup *,art_num,art_num, Boolean, int *)); +extern Boolean getapprovedlist _ARGUMENTS((struct newsgroup *,art_num,art_num, + Boolean, int *)); /* xhdr commands */ diff -ruNP xrn-9.01/snapshot.c xrn-9.02/snapshot.c --- xrn-9.01/snapshot.c Thu Jun 5 07:11:42 1997 +++ xrn-9.02/snapshot.c Fri May 29 13:15:08 1998 @@ -73,8 +73,7 @@ int i, byte, bit, mask; struct article *art, copy; - assert(group && !strcmp(group, newsgroup->name) && - (first == newsgroup->first) && (last == newsgroup->last)); + assert(group && !strcmp(group, newsgroup->name) && (first == newsgroup->first) && (last == newsgroup->last)); for (i = first; i <= last; i++) { art = artStructGet(newsgroup, i, False); diff -ruNP xrn-9.01/sort.c xrn-9.02/sort.c --- xrn-9.01/sort.c Tue May 12 12:54:12 1998 +++ xrn-9.02/sort.c Fri Jul 10 09:41:43 1998 @@ -300,7 +300,7 @@ for (i = 0; i < data->count; i++) { hash_reference = HASH_NO_VALUE; - if ((hash_return = + if ((void *)(hash_return = hash_table_retrieve(hash_table, (void *)data->articles[i].sort_key, &hash_reference)) == HASH_NO_VALUE) { diff -ruNP xrn-9.01/utils.h xrn-9.02/utils.h --- xrn-9.01/utils.h Mon Apr 6 07:41:06 1998 +++ xrn-9.02/utils.h Fri Jul 10 17:56:21 1998 @@ -2,7 +2,7 @@ #define UTILS_H /* - * $Id: utils.h,v 1.57 1998/04/06 11:41:06 jik Exp $ + * $Id: utils.h,v 1.58 1998/07/10 21:56:21 jik Exp $ */ /* @@ -160,11 +160,15 @@ #define SIG_RET_T int #endif -#if defined(_ANSI_C_SOURCE) || defined(linux) || defined(__bsdi__) || defined(SOLARIS) || defined(__hpux) +#ifdef sgi +typedef SIG_RET_T (*SIG_PF0) _ARGUMENTS((void)); +#else /* ! sgi */ +# if defined(_ANSI_C_SOURCE) || defined(linux) || defined(__bsdi__) || defined(SOLARIS) || defined(__hpux) typedef SIG_RET_T (*SIG_PF0) _ARGUMENTS((int)); -#else /* ! _ANSI_C_SOURCE */ +# else /* ! _ANSI_C_SOURCE */ typedef SIG_RET_T (*SIG_PF0) _VARARGUMENTS((int, ...)); -#endif /* _ANSI_C_SOURCE */ +# endif /* _ANSI_C_SOURCE */ +#endif /* sgi */ #undef SIG_RET_T diff -ruNP xrn-9.01/xrn-man.src xrn-9.02/xrn-man.src --- xrn-9.01/xrn-man.src Mon May 25 11:12:44 1998 +++ xrn-9.02/xrn-man.src Fri Sep 24 10:23:43 1999 @@ -1,5 +1,5 @@ -.TH XRN 1 "$Date: 1998/05/25 15:12:43 $" "X" -.\" $Id: xrn-man.src,v 1.214 1998/05/25 15:12:43 jik Exp $ +.TH XRN 1 "$Date: 1999/09/24 14:23:43 $" "X" +.\" $Id: xrn-man.src,v 1.223 1999/09/24 14:23:43 jik Exp $ .\" .\" xrn - an X-based NNTP news reader .\" @@ -42,7 +42,7 @@ users to read news from personal workstations by accessing a central news repository. -This manual page applies to version 9.01. +This manual page applies to version 9.02. .\" .SH DESCRIPTION .PP @@ -1296,12 +1296,12 @@ .TP 10 .B \-includePrefix "prefix text" Change the standard prefix for each line of included text from the -default, "|> ", to the given text string. +default, ">", to the given text string. .TP 10 .B +/\-includeSep -Include or do not include the prefix text ("|> ") in front of included +Include or do not include the prefix text (">") in front of included articles. -The default is to include the prefix text ("|> "). +The default is to include the prefix text (">"). .TP 10 .B +/\-info Display all informative messages in the message pane. @@ -1579,7 +1579,7 @@ .TP 10 .B \-verboseKill actions By default, when processing kill files, the subject of each article -that is marked read, marked unread, or saved is displayed, and a +that is marked read, marked unread, saved, or thread-killed is displayed, and a summary of all such articles is displayed when done processing the kill file. This option allows you to select which subjects and summaries to display. The @@ -1587,8 +1587,9 @@ specified should contain one or more of `l', `j', `m' and `s'. `l' means to display each kill-file pattern as it is processed. `j' means to display articles that are marked read, `m' means to display -articles that are marked unread, and `s' means to display articles -that are saved. If +articles that are marked unread, `s' means to display articles that +are saved, and `t' means to display articles whose subthreads or +threads are added to the kill file. If .B actions is empty, then no information is displayed when processing kill files. .TP 10 @@ -1691,14 +1692,17 @@ .I ir kill files. .IP command -A single letter, either `j' (mark the article read), `m' (mark the -article unread), or `s' (save the article in the default save file for -the newsgroup). +One of `j' (mark the article read), `m' (mark the article unread), or +`s' (save the article in the default save file for the newsgroup), `t' +(insert a kill-file entry for this subthread in the local kill file), +or `T' (insert a kill-file entry for this thread in the local kill +file). .PP If the first character in the options field is `h', then \*(XR will check to see if the regular expression starts with "^From:", "^Subject:", "^Newsgroups:", "^Date:", "^Message-ID:", "^References:", -or "^Xref:". If it does, then the pattern will be matched against the +"^Xref:", or "Approved:". If it does, then the pattern will be +matched against the corresponding header field in the article. The comparison will be "anchored", that is, the pattern must match from the beginning of the field value in order to be considered a match. @@ -1715,7 +1719,7 @@ compared against all of the fields mentioned above. Note that normally, \*(XR doesn't fetch the "Newsgroups", "Date", -"Message-ID", "References", or "Xref" fields of articles; it fetches +"Message-ID", "References", "Xref", or "Approved" fields of articles; it fetches them only when it notices while processing a kill file entry that they are needed. Therefore, specifying kill file entries which must be matched against one of those fields may cause \*(XR to take longer to @@ -1738,6 +1742,17 @@ .BR X (1) for information about setting any X resource from the command line): +.TP 10 +.B authenticateOnConnect +Some News servers expect you to send your authentication information +when you connect, even though they don't explicitly ask for it like +they're supposed to. If you are trying to use authentication as +described above (see the "authenticatorCommand" option), and \*(XR +never prompts for your authentication information (e.g., your username +and password) or you can't see all of the newsgroups that you're +supposed to see, try setting this resource to true, and \*(XR will +always do authentication immediately after connecting to the News +server. .TP 10 .B buttonsOnTop By default, \*(XR arranges its window in such a way that button boxes