[tin 1.7.x] CAPABILITIES 'framework'

Urs Janßen <[email protected]>
Newsgroups gmane.network.tin.devel
Message-ID <[email protected]>
the following patch over the last snap could be used as a
startingpoint to use the new CAPABILITIES cmd and avoid trying
commands to see if they are supported. it introduces a new global
(sigh) struct which holds all the infos (global cause the
nntp-actions are scattered all over the code). comments welcome.

urs
-- 
"Only whimps use tape backup: _real_ men just upload their important stuff
 on ftp, and let the rest of the world mirror it ;)" - Linus
yy (text/plain, 21.2 KB)
 include/extern.h  |    1 
 include/nntplib.h |   26 +++++
 include/proto.h   |    3 
 src/art.c         |   10 +-
 src/debug.c       |   15 +++
 src/filter.c      |    4 
 src/init.c        |   22 ++++
 src/main.c        |    6 -
 src/misc.c        |    2 
 src/nntplib.c     |  240 ++++++++++++++++++++++++++++++++++++++++++------------
 src/post.c        |    2 
 src/xref.c        |    2 
 12 files changed, 268 insertions(+), 65 deletions(-)
diff -Nurp tin-1.7.9.snap/include/extern.h tin-1.7.9.new/include/extern.h
--- tin-1.7.9.snap/include/extern.h	2005-04-12 16:49:02.000000000 +0200
+++ tin-1.7.9.new/include/extern.h	2005-05-04 14:32:30.000000000 +0200
@@ -1272,6 +1272,7 @@ extern struct t_group *curr_group;
 extern struct t_newnews *newnews;
 extern struct t_option option_table[];
 extern struct t_save *save;
+extern struct t_capabilities nntp_caps;
 
 extern t_bool *OPT_ON_OFF_list[];
 extern t_bool can_post;
diff -Nurp tin-1.7.9.snap/include/nntplib.h tin-1.7.9.new/include/nntplib.h
--- tin-1.7.9.snap/include/nntplib.h	2005-04-09 00:45:23.000000000 +0200
+++ tin-1.7.9.new/include/nntplib.h	2005-05-04 14:57:17.000000000 +0200
@@ -166,4 +166,30 @@
  */
 #define NNTP_STRLEN		512
 
+/*
+ * CAPABILITIES
+ */
+struct t_capabilities {
+	unsigned int type:4;				/* none, LIST EXTENSIONS, CAPABILITIES */
+	unsigned int version;			/* CAPABILITIES version */
+	t_bool mode_reader:1;			/* MODE-READER: "MODE READER" */
+	t_bool reader:1;					/* READER: "LISTGROUP" & co. */
+	t_bool post:1;						/* POST: "POST" */
+	t_bool ihave:1;					/* IHAVE: "IHAVE" */
+	t_bool list_active:1;			/* LIST ACTIVE */
+	t_bool list_active_times:1;	/* LIST ACTIVE.TIMES, optional */
+	t_bool list_distrib_pats:1;	/* LIST DISTRIB.PATS, optional */
+	t_bool list_headers:1;			/* LIST HEADERS */
+	t_bool list_newsgroups:1;		/* LIST NEWSGROUPS */
+	t_bool list_motd:1;				/* LIST MOTD, "private" extension */
+	t_bool list_subscriptions:1;	/* LIST SUBSCRIPTIONS, "private" extension */
+	t_bool hdr:1;						/* HDR: "HDR", "LIST HEADERS" */
+	const char *hdr_cmd;				/* [X]HDR */
+	t_bool over:1;						/* OVER: "OVER", "LIST OVERVIEW.FMT" */
+	const char *over_cmd;			/* [X]OVER */
+	t_bool newnews:1;					/* NEWNEWS */
+	char *implementation;			/* IMPLEMENTATION */
+	/* AUTHINFO, SASL, STARTTLS, STREAMING */
+};
+
 #endif /* !NNTPLIB_H */
diff -Nurp tin-1.7.9.snap/include/proto.h tin-1.7.9.new/include/proto.h
--- tin-1.7.9.snap/include/proto.h	2005-04-14 14:32:00.000000000 +0200
+++ tin-1.7.9.new/include/proto.h	2005-05-04 15:49:21.000000000 +0200
@@ -161,6 +161,9 @@ extern void word_highlight_string(int ro
 	extern void debug_print_filters(void);
 	extern void debug_print_header(struct t_article *s);
 	extern void debug_print_malloc(int is_malloc, const char *xfile, int line, size_t size);
+#	ifdef NNTP_ABLE
+		extern void debug_print_nntp_extensions(void);
+#	endif /* NNTP_ABLE */
 #endif /* DEBUG */
 #ifdef DEBUG_NEWSRC
 	extern void debug_print_newsrc(struct t_newsrc *NewSrc, FILE *fp);
diff -Nurp tin-1.7.9.snap/src/art.c tin-1.7.9.new/src/art.c
--- tin-1.7.9.snap/src/art.c	2005-04-09 00:45:24.000000000 +0200
+++ tin-1.7.9.new/src/art.c	2005-05-04 15:48:04.000000000 +0200
@@ -390,7 +390,7 @@ index_group(
 	 * When reading local spool, this will pull in the system wide overview
 	 * cache (if found) otherwise the private overview cache will be read
 	 */
-	caching_xover = (tinrc.cache_overview_files && xover_cmd && group->type == GROUP_TYPE_NEWS);
+	caching_xover = (tinrc.cache_overview_files && nntp_caps.over_cmd && group->type == GROUP_TYPE_NEWS);
 	if ((changed = read_overview(group, min, max, &last_read_article, caching_xover)) == -1)
 		return FALSE;	/* user aborted indexing */
 
@@ -1654,8 +1654,8 @@ find_nov_file(
 
 		case GROUP_TYPE_NEWS:
 			/*
-			 * xover_cmd is not an issue here, any gripes and warnings
-			 * about XOVER are handled in nntp_open()
+			 * nntp.caps.over_cmd is not an issue here, any gripes and warnings
+			 * about [X]OVER are handled in nntp_open()
 			 */
 
 			/*
@@ -2216,10 +2216,10 @@ open_xover_fp(
 	t_bool local)
 {
 #ifdef NNTP_ABLE
-	if (!local && xover_cmd && *mode == 'r' && group->type == GROUP_TYPE_NEWS) {
+	if (!local && nntp_caps.over_cmd && *mode == 'r' && group->type == GROUP_TYPE_NEWS) {
 		char line[NNTP_STRLEN];
 
-		snprintf(line, sizeof(line), "%s %ld-%ld", xover_cmd, min, max);
+		snprintf(line, sizeof(line), "%s %ld-%ld", nntp_caps.over_cmd, min, max);
 		return (nntp_command(line, OK_XOVER, NULL, 0));
 	}
 #endif /* NNTP_ABLE */
diff -Nurp tin-1.7.9.snap/src/debug.c tin-1.7.9.new/src/debug.c
--- tin-1.7.9.snap/src/debug.c	2005-04-09 00:45:24.000000000 +0200
+++ tin-1.7.9.new/src/debug.c	2005-05-04 15:49:05.000000000 +0200
@@ -330,6 +330,21 @@ debug_print_filters(
 		fclose(fp);
 	}
 }
+
+
+#	ifdef NNTP_ABLE
+void
+debug_print_nntp_extensions(
+	void)
+{
+	if (debug < 2)
+		return;
+	debug_nntp("###", "NNTP CAPABILITIES/EXTENSIONS");
+	debug_nntp("###", "Type/Version : %d/%d", nntp_caps.type, nntp_caps.version);
+	debug_nntp("###", "Command-names: %s %s", BlankIfNull(nntp_caps.over_cmd), BlankIfNull(nntp_caps.hdr_cmd));
+	debug_nntp("###", "List         : %s", nntp_caps.list_motd ? "MOTD" : "");
+}
+#	endif /* NNTP_ABLE */
 #endif /* DEBUG */
 
 #ifdef DEBUG_NEWSRC
diff -Nurp tin-1.7.9.snap/src/filter.c tin-1.7.9.new/src/filter.c
--- tin-1.7.9.snap/src/filter.c	2005-04-09 00:45:26.000000000 +0200
+++ tin-1.7.9.new/src/filter.c	2005-05-04 15:48:54.000000000 +0200
@@ -2173,10 +2172,10 @@ open_xhdr_fp(
 	long max)
 {
 #	ifdef NNTP_ABLE
-	if (read_news_via_nntp && !read_saved_news && xhdr_cmd) {
+	if (read_news_via_nntp && !read_saved_news && nntp_caps.hdr_cmd) {
 		char buf[NNTP_STRLEN];
 
-		snprintf(buf, sizeof(buf), "%s %s %ld-%ld", xhdr_cmd, header, min, max);
+		snprintf(buf, sizeof(buf), "%s %s %ld-%ld", nntp_caps.hdr_cmd, header, min, max);
 		return (nntp_command(buf, OK_HEAD, NULL, 0));
 	} else
 #	endif /* NNTP_ABLE */
diff -Nurp tin-1.7.9.snap/src/init.c tin-1.7.9.new/src/init.c
--- tin-1.7.9.snap/src/init.c	2005-04-09 00:45:24.000000000 +0200
+++ tin-1.7.9.new/src/init.c	2005-05-04 14:49:26.000000000 +0200
@@ -419,6 +419,28 @@ struct t_config tinrc = {
 #endif /* HAVE_LIBICUUC && MULTIBYTE_ABLE && HAVE_UNICODE_UBIDI_H && !NO_LOCALE */
 };
 
+struct t_capabilities nntp_caps = {
+	0, /* type (none, LIST EXTENSIONS, CAPABILITIES) */
+	0, /* CAPABILITIES version */
+	FALSE, /* MODE-READER: "MODE READER" */
+	FALSE, /* READER: "LISTGROUPS" & co. */
+	FALSE, /* POST */
+	FALSE, /* IHAVE */
+	FALSE, /* LIST: "LIST ACTIVE" */
+	FALSE, /* LIST: "LIST ACTIVE.TIMES" */
+	FALSE, /* LIST: "LIST DISTRIB.PATS" */
+	FALSE, /* LIST: "LIST HEADERS" */
+	FALSE, /* LIST: "LIST NEWSGROUPS" */
+	FALSE, /* LIST: "LIST MOTD" */
+	FALSE, /* LIST: "LIST SUBSCRIPTIONS" */
+	FALSE, /* HDR: "HDR", "LIST HEADERS" */
+	NULL, /* [X]HDR */
+	FALSE, /* OVER: "OVER", "LIST OVERVIEW.FMT" */
+	NULL, /* [X]OVER */
+	FALSE, /* NEWNEWS */
+	NULL	/* IMPLEMENTATION */	
+};
+         
 static mode_t real_umask;
 
 #ifdef HAVE_COLOR
diff -Nurp tin-1.7.9.snap/src/main.c tin-1.7.9.new/src/main.c
--- tin-1.7.9.snap/src/main.c	2005-04-14 14:31:33.000000000 +0200
+++ tin-1.7.9.new/src/main.c	2005-05-04 15:48:16.000000000 +0200
@@ -187,9 +187,9 @@ main(
 
 	/*
 	 * exit early - unfortunately we can't do that in read_cmd_line_options()
-	 * as xover_cmd is set in nntp_open()
+	 * as nntp_caps.over_cmd is set in nntp_open()
 	 */
-	if (update_index && xover_cmd && !tinrc.cache_overview_files) {
+	if (update_index && nntp_caps.over_cmd && !tinrc.cache_overview_files) {
 		error_message(_(txt_batch_update_unavail), tin_progname);
 		giveup();
 	}
@@ -197,7 +197,7 @@ main(
 	/*
 	 * Check if overview indexes contain Xref: lines
 	 */
-	if (xover_cmd)
+	if (nntp_caps.over_cmd)
 		xref_supported = overview_xref_support();
 
 #ifdef DEBUG_NEWSRC
diff -Nurp tin-1.7.9.snap/src/misc.c tin-1.7.9.new/src/misc.c
--- tin-1.7.9.snap/src/misc.c	2005-04-09 00:45:26.000000000 +0200
+++ tin-1.7.9.new/src/misc.c	2005-05-04 15:48:28.000000000 +0200
@@ -2029,7 +2029,7 @@ cleanup_tmp_files(
 #if 0
 	char acNovFile[PATH_LEN];
 
-	if (xover_cmd && !tinrc.cache_overview_files) {
+	if (nntp_caps.over_cmd && !tinrc.cache_overview_files) {
 		snprintf(acNovFile, sizeof(acNovFile), "%s%d.idx", TMPDIR, (int) process_id);
 		unlink(acNovFile);
 	}
diff -Nurp tin-1.7.9.snap/src/nntplib.c tin-1.7.9.new/src/nntplib.c
--- tin-1.7.9.snap/src/nntplib.c	2005-04-09 00:45:25.000000000 +0200
+++ tin-1.7.9.new/src/nntplib.c	2005-05-04 16:04:38.000000000 +0200
@@ -30,7 +30,6 @@
 #endif /* VMS */
 
 char *nntp_server = NULL;
-constext *xover_cmd = NULL;
 #ifdef NO_POSTING
 	t_bool can_post = FALSE;
 #else
@@ -48,11 +47,9 @@
 	static char last_put[NNTP_STRLEN];
 	static constext *xover_cmds = "XOVER";
 #	if 0 /* currently not used */
-	static constext *xhdr_cmd = NULL;
 	static constext *xhdr_cmds = "XHDR";
 #	endif /* 0 */
 	enum extension_type { NO, LIST_EXTENSIONS, CAPABILITIES };
-	static int have_list_extensions = NO;
 	/* Set so we don't reconnect just to QUIT */
 	static t_bool quitting = FALSE;
 #endif /* NNTP_ABLE */
@@ -66,6 +63,7 @@
 	static int server_init(char *machine, const char *cservice, int port, char *text, size_t mlen);
 	static void check_extensions(void);
 	static void close_server(void);
+	static void list_motd(void);
 #	ifdef INET6
 		static int get_tcp6_socket(char *machine, unsigned short port);
 #	else
@@ -769,13 +767,12 @@
  * Returns: Nothing.
  *
  *	Side effects: Talks to the server.
- *			Closes connection if things are not right.
+ *	              Closes connection if things are not right.
  *
  * Note: This routine flushes the buffer each time it is called. For large
  *	      transmissions (i.e., posting news) don't use it. Instead, do the
  *	      fprintf's yourself, and then a final fflush.
  *       Only cache commands, don't cache data transmissions.
- *
  */
 void
 put_server(
@@ -958,7 +955,7 @@
  * issuing other NNTP commands because the correct methods may be mentioned
  * in the list of extensions.
  *
- * Sets up: have_list_extensions, xover_cmd, (xhdr_cmd)
+ * Sets up: t_capabilities nntp_caps
  */
 static void
 check_extensions(
@@ -968,56 +965,131 @@
 	int i;
 #	if 0 /* "CAPABILITIES" will replace "LIST EXTENSIONS" */
 	FILE *fp;
+	char *d;
 
-	if ((fp = nntp_command("CAPABILITIES", INF_CAPABILITIES, NULL, 0)) != NULL) {
-		int cap_version = -1;
+	/*
+	 * VERSION
+	 *   This capability MUST be advertised by all servers and MUST be the
+	 *   first capability in the capability list; it indicates the version(s)
+	 *   of NNTP that the server supports. There must be at least one
+	 *   argument; each argument is a decimal number and MUST NOT have a
+	 *   leading zero.
+	 * READER
+	 *   This capability indicates that the server implements the
+	 *   various commands useful for reading clients, e.g. LISTGROUP
+	 * IHAVE
+	 *   This capability indicates that the server implements the
+	 *   IHAVE command.
+	 * POST
+	 *   This capability indicates that the server implements the
+	 *   POST command.
+	 * NEWNEWS
+	 *   This capability indicates that the server implements the
+	 *   NEWNEWS command.
+	 * HDR
+	 *   This capability indicates that the server implements the
+	 *   header access commands (HDR and LIST HEADERS).
+	 * OVER
+	 *   This capability indicates that the server implements the
+	 *   overview access commands (OVER and LIST OVERVIEW.FMT). If
+	 *   and only if the server supports the message-id form of the
+	 *   OVER command, there must be a single argument MSGID.
+	 * LIST
+	 *   This capability indicates that the server implements at
+	 *   least one variant of the LIST command. There MUST be one
+	 *   argument for each variant of the LIST command supported by
+	 *   the server, giving the keyword for that variant.
+	 * IMPLEMENTATION
+	 *   This capability MAY be provided by a server. If so, the
+	 *   arguments SHOULD be used to provide information such as the
+	 *   server software name and version number. The client MUST
+	 *   NOT use this line to determine capabilities of the server.
+	 *   (While servers often provide this information in the
+	 *   initial greeting, clients need to guess whether this is the
+	 *   case; this capability makes it clear what the information
+	 *   is.)
+	 * MODE-READER
+	 *   This capability indicates that the server is mode-switching
+	 *   (Mode switching) and the MODE READER command needs to be
+	 *   used to enable the READER capability.
+	 * AUTHINFO
+	 * SASL
+	 * STARTTLS
+	 * STREAMING
+	 */
 
-		have_list_extensions = CAPABILITIES;
+	if ((fp = nntp_command("CAPABILITIES", INF_CAPABILITIES, NULL, 0)) != NULL) {
+		nntp_caps.type = CAPABILITIES;
 		while ((ptr = tin_fgets(fp, FALSE)) != NULL) {
 #		ifdef DEBUG
 			debug_nntp("<<<", ptr);
 #		endif /* DEBUG */
-			/* look for version number */
-			if (cap_version == -1 && have_list_extensions == CAPABILITIES) {
-				if (!strncasecmp(ptr, "VERSION", 7))
-					cap_version = atoi(ptr + 8);
+			/* look for version number(s) */
+			if (!nntp_caps.version && nntp_caps.type == CAPABILITIES) {
+				if (!strncasecmp(ptr, "VERSION", 7)) {
+					d = ptr + 7;
+					d = strpbrk(d, " \t");
+					while (d != NULL && (d + 1 < (ptr + strlen(ptr)))) {
+						d++;
+						nntp_caps.version = MAX(nntp_caps.version, (unsigned int) atoi(d));
+						d = strpbrk(d, " \t");
+					}
+				}
 			}
 			/* we currently only support CAPABILITIES VERSION 2 */
-			if (cap_version == 2) {
+			if (nntp_caps.version == 2) {
 				/*
-				 * Check for (X)OVER
-				 * XOVER should not be listed in CAPABILITIES
-				 * but checking for it if OVER is not found does no harm.
+				 * check for LIST variants - this code is untested
 				 */
-				if (!xover_cmd) {
-					for (i = 1; i >= 0; i--) {
-						if (strcasecmp(ptr, &xover_cmds[i]) == 0) {
-							xover_cmd = &xover_cmds[i];
-							break;
+				if (strncasecmp(ptr, "LIST", 4) == 0) {
+					d = ptr + 4;
+					d = strpbrk(d, " \t");
+					while (d != NULL && (d + 1 < (ptr + strlen(ptr)))) {
+						d++;
+						if (strncasecmp(d, "ACTIVE.TIMES", 12) == 0)
+							nntp_caps.list_active_times = TRUE;
+						else if (strncasecmp(d, "ACTIVE", 6) == 0)
+							nntp_caps.list_active_times = TRUE;
+						else if (strncasecmp(d, "DISTRIB.PATS", 12) == 0)
+							nntp_caps.list_distrib_pats = TRUE;
+						else if (strncasecmp(d, "HEADERS", 7) == 0) {
+							nntp_caps.list_headers = TRUE;
+							nntp_caps.hdr = TRUE;
 						}
+						else if (strncasecmp(d, "NEWSGROUPS", 10) == 0)
+							nntp_caps.list_newsgroups = TRUE;
+						else if (strncasecmp(d, "MOTD", 4) == 0)
+							nntp_caps.list_motd = TRUE;
+						else if (strncasecmp(d, "SUBSCRIPTIONS", 13) == 0)
+							nntp_caps.list_subscriptions = TRUE;
+						d = strpbrk(d, " \t");
 					}
 				}
+
+				/*
+				 * NOTE: if we saw OVER, LIST OVERVIEW.FMT _must_ be implemented
+				 */
+				else if (strcasecmp(ptr, &xover_cmds[1]) == 0) {
+					nntp_caps.over = TRUE;
+					nntp_caps.over_cmd = &xover_cmds[1];
+				}
+
 #		if 0 /* currently not used */
 				/*
-				 * Check for (X)HDR
-				 * XHDR should not be listed in EXTENSIONS (but sometimes is)
-				 * checking for it if HDR is not found does no harm.
+				 * NOTE: if we saw HDR, LIST HEADERS _must_ be implemented
 				 */
-				if (!xhdr_cmd) {
-					for (i = 1; i >= 0; i--) {
-						if (strcasecmp(ptr, &xhdr_cmds[i]) == 0) {
-							xhdr_cmd = &xhdr_cmds[i];
-							break;
-						}
-					}
+				else if (strcasecmp(ptr, &xhdr_cmds[1]) == 0) {
+						nntp_caps.hdr_cmd = &xhdr_cmds[1];
+						nntp_caps.hdr = TRUE;
+						nntp_caps.list_headers = TRUE;
 				}
-#		endif /* 0 */
 				/*
-				 * LIST, READER, SASL, STARTTLS, STREAMING, AUTHINFO, IHAVE
-				 * IMPLEMENTATION, (MODE-READER)
+				 * MODE-READER, READER, POST, IHAVE, NEWNEWS, IMPLEMENTATION
+				 * AUTHINFO, SASL, STARTTLS, STREAMING
 				 */
+#		endif /* 0 */
 			} else
-				have_list_extensions = NO;
+				nntp_caps.type = NO;
 		}
 	}
 #	endif /* 0 */
@@ -1027,19 +1099,18 @@
 	 * "LIST EXTENSIONS" is somewhat troublesome as there are a lot
 	 * of broken implementations out there and it is a multiline response
 	 */
-	if (have_list_extensions == NO) {
+	if (nntp_caps.type == NO) {
 		char buf[NNTP_STRLEN];
 
 		buf[0] = '\0';
 		i = new_nntp_command("LIST EXTENSIONS", OK_EXTENSIONS, buf, sizeof(buf));
 		switch (i) {
 			case OK_EXTENSIONS:	/* as defined draft-ietf-nntpext-base-24.txt */
-				have_list_extensions = LIST_EXTENSIONS;
-				/* FALLTHROUGH */
 			case 205:	/* M$ Exchange 5.5 */
-			case 215:	/* Netscape-Collabra/3.52 && NetWare-News-Server/5.1*/
+			case 215:	/* Netscape-Collabra/3.52 && NetWare-News-Server/5.1 */
+				nntp_caps.type = LIST_EXTENSIONS;
 				while ((ptr = tin_fgets(FAKE_NNTP_FP, FALSE)) != NULL) {
-					if (have_list_extensions == LIST_EXTENSIONS) {
+					if (nntp_caps.type == LIST_EXTENSIONS) {
 #		ifdef DEBUG
 						debug_nntp("<<<", ptr);
 #		endif /* DEBUG */
@@ -1053,16 +1124,22 @@
 						 * XOVER should not be listed in EXTENSIONS (but sometimes is)
 						 * checking for it if OVER is not found does no harm.
 						 */
-						if (!xover_cmd) {
+						if (!nntp_caps.over_cmd) {
 							for (i = 1; i >= 0; i--) {
 								if (strcasecmp(ptr, &xover_cmds[i]) == 0) {
-									xover_cmd = &xover_cmds[i];
+									nntp_caps.over_cmd = &xover_cmds[i];
 									break;
 								}
 							}
 						}
 					}
 				}
+				/*
+				 * as we did support LIST EXTENSIONS it's likely that we
+				 * also can do LIST MOTD (we don't bother to parse the
+				 * LIST EXTENSIONS output as it never was standartizised)
+				 */
+				nntp_caps.list_motd = TRUE;
 				break;
 
 			default:
@@ -1070,6 +1147,9 @@
 			}
 		}
 #	endif /* 1 */
+#	ifdef DEBUG
+	debug_print_nntp_extensions();
+#	endif /* DEBUG */
 	return;
 }
 #endif /* NNTP_ABLE */
@@ -1317,35 +1397,35 @@
 	 * (successor of XOVER as of latest NNTP Draft (Jan 2002)
 	 * We have to check that we _don't_ get an ERR_COMMAND
 	 */
-	if (have_list_extensions == NO) {
+	if (nntp_caps.type == NO) {
 		for (i = 0; i < 2; i++) {
 			if (!nntp_command(&xover_cmds[i], ERR_COMMAND, NULL, 0)) {
-				xover_cmd = &xover_cmds[i];
+				nntp_caps.over_cmd = &xover_cmds[i];
 				break;
 			}
 		}
 	} else {
-		if (!xover_cmd) {
+		if (!nntp_caps.over_cmd) {
 			/*
 			 * LIST EXTENSIONS didn't mention OVER or XOVER, try
 			 * XOVER
 			 */
 			if (!nntp_command(xover_cmds, ERR_COMMAND, NULL, 0))
-				xover_cmd = xover_cmds;
+				nntp_caps.over_cmd = xover_cmds;
 		}
 #	if 0 /* unused */
-		if (!xhdr_cmd) {
+		if (!nntp_caps.hdr_cmd) {
 			/*
 			 * LIST EXTENSIONS didn't mention HDR or XHDR, try
 			 * XHDR
 			 */
 			if (!nntp_command(xhdr_cmds, ERR_COMMAND, NULL, 0))
-				xhdr_cmd = xhdr_cmds;
+				nntp_caps.hdr_cmd = xhdr_cmds;
 		}
 #	endif /* 0 */
 	}
 
-	if (!xover_cmd) {
+	if (!nntp_caps.over_cmd) {
 		if (!is_reconnect && !batch_mode) {
 			wait_message(2, _(txt_no_xover_support));
 
@@ -1365,14 +1445,24 @@
 
 #	if 0
 	/*
-	 * TODO: if we're using -n, check for LIST NEWSGROUPS <wildmat> */
-	 * see also comments in open_newsgroups_fp() */
+	 * TODO: if we're using -n, check for LIST NEWSGROUPS <wildmat>
+	 * see also comments in open_newsgroups_fp()
 	 */
 	if (newsrc_active && !list_active) { /* -n */
 		/* code goes here */
 	}
 #	endif /* 0 */
 
+	if (!is_reconnect && !batch_mode && show_description && check_for_new_newsgroups) {
+		/*
+		 * TODO:
+		 * - document that "-d" and/or "-q" turns off "LIST MOTD" (or add
+		 *   a tinrc var to turn LIST MOTD on/off)
+		 */
+		if (nntp_caps.list_motd)
+			list_motd();
+	}
+
 	is_reconnect = TRUE;
 
 #endif /* NNTP_ABLE */
@@ -1598,4 +1688,50 @@
 #	endif /* DEBUG */
 	return respcode;
 }
+
+
+static void
+list_motd(
+	void)
+{
+	char *ptr;
+	char buf[NNTP_STRLEN];
+	int i;
+	unsigned int l = 0;
+
+	buf[0] = '\0';
+	i = new_nntp_command("LIST MOTD", OK_MOTD, buf, sizeof(buf));
+
+	switch (i) {
+		case OK_MOTD:
+#	ifdef HAVE_COLOR
+			fcol(tinrc.col_message);
+#	endif /* HAVE_COLOR */
+			while ((ptr = tin_fgets(FAKE_NNTP_FP, FALSE)) != NULL) {
+#	ifdef DEBUG
+				debug_nntp("<<<", ptr);
+#	endif /* DEBUG */
+				/*
+				 * TODO: - store a hash value of the entire motd in the server-rc
+				 *         and only if it differs from the old value display the
+				 *         motd?
+				 *       - use some sort of pager?
+				 *       - -> lang.c
+				 */
+				my_printf("%s%s\n", _("MOTD: "), ptr);
+				l++;
+			}
+#	ifdef HAVE_COLOR
+			fcol(tinrc.col_normal);
+#	endif /* HAVE_COLOR */
+			if (l) {
+				my_flush();
+				sleep((l >> 1) | 0x01);
+			}
+			break;
+
+		default:	/* common response codes are 500, 501, 503 */
+			break;
+	}
+}
 #endif /* NNTP_ABLE */
diff -Nurp tin-1.7.9.snap/src/post.c tin-1.7.9.new/src/post.c
--- tin-1.7.9.snap/src/post.c	2005-04-09 00:45:26.000000000 +0200
+++ tin-1.7.9.new/src/post.c	2005-05-04 15:47:41.000000000 +0200
@@ -3040,7 +3041,7 @@ mail_bug_report(
 		DEFAULT_ACTIVE_NUM,
 		DEFAULT_ARTICLE_NUM,
 		tinrc.reread_active_file_secs,
-		bool_unparse(xover_cmd != NULL));
+		bool_unparse(nntp_caps.over_cmd != NULL));
 	fprintf(fp, "CFG2 : debug=%d, threading=%d\n", debug, tinrc.thread_articles);
 	fprintf(fp, "CFG3 : domain=[%s]\n", BlankIfNull(domain));
 	start_line_offset += 4;
diff -Nurp tin-1.7.9.snap/src/xref.c tin-1.7.9.new/src/xref.c
--- tin-1.7.9.snap/src/xref.c	2005-04-09 00:45:24.000000000 +0200
+++ tin-1.7.9.new/src/xref.c	2005-05-04 15:48:38.000000000 +0200
@@ -62,7 +62,7 @@ open_overview_fmt_fp(
 
 #ifdef NNTP_ABLE
 	if (read_news_via_nntp && !read_saved_news) {
-		if (!xover_cmd)
+		if (!nntp_caps.over_cmd)
 			return (FILE *) 0;
 
 		snprintf(line, sizeof(line), "LIST %s", OVERVIEW_FMT);
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.