Rough draft patch: slrnpull configuration to immediately retry posts.

Seebs <[email protected]> Thu, 19 Sep 2013 20:28:15 -0500
Newsgroups gmane.network.slrn.user
Message-ID <[email protected]>
So, I have noticed a strange transient failure with one particular 
Usenet server, which is that after authentication, there is sometimes 
but not always a window during which any post submitted to it will be 
rejected with "441 436 <message-id>" and no other explanation.

Browsing around, I've found one claim that a server exists which does 
this for duplicate posts. In this case, though, it's definitely not 
duplicates, it's brand-new posts with suitably-unique message IDs. It 
may also occasionally show up for other reasons.

Solution: Retry failed posts. So I've produced a patch which will retry 
posts if configured to do so through a line in slrnpull.conf reading 
"nntp-retries 3 10". (3 being the number of retries, 10 being the number 
of seconds to delay before retrying).

This is probably inadequately tested, but it solved my immediate 
problem, so I figured I'd send it out for evaluation, in case it was 
useful to someone else.

-s

------------------------------------------------------------------------------
LIMITED TIME SALE - Full Year of Microsoft Training For Just $49.99!
1,500+ hours of tutorials including VisualStudio 2012, Windows 8, SharePoint
2013, SQL 2012, MVC 4, more. BEST VALUE: New Multi-Library Power Pack includes
Mobile, Cloud, Java, and UX Design. Lowest price ever! Ends 9/20/13. 
http://pubads.g.doubleclick.net/gampad/clk?id=58041151&iu=/4140/ostg.clktrk
retry_436.patch (application/octet-stream, 3.6 KB)
commit a55e2fc12301e0694452af46e11f52d590b4ccff
Author: Seebs <[email protected]>
Date:   Thu Sep 19 20:18:44 2013 -0500

    Allow retrying NNTP submissions
    
    One usenet server I occasionally interact with has the very
    curious trait that an article submission too early in a session
    will almost always result in a "441 436" response. Simply
    retrying once or twice will usually get a successful post.
    
    This patch adds an optional "nntp-retries" configuration
    hook for slrnpull.conf, which allows the user to request that
    NNTP submissions be retried a couple of times before giving
    up.
    
    Signed-off-by: Seebs <[email protected]>

diff --git a/src/slrnpull.c b/src/slrnpull.c
index fb40a9a..f2669b8 100644
--- a/src/slrnpull.c
+++ b/src/slrnpull.c
@@ -142,6 +142,7 @@ static int Use_Fetch_Score;
 static int Kill_Score;
 static char *Active_Groups_File;
 static time_t Start_Time;
+static int nntp_retries = 0, nntp_retry_interval = 0;
 
 #define CREATE_OVERVIEW 1
 
@@ -736,6 +737,14 @@ static int read_active_groups (void) /*{{{*/
 	     continue;
 	  }
 
+        if (0 == strcmp (name, "nntp-retries"))
+	  {
+	     /* repurpose the first two fields */
+	     nntp_retries = max_to_get;
+	     nntp_retry_interval = expire_days;
+	     continue;
+	  }
+
 	if (NULL != find_group_type (name))
 	  {
 	     log_error (_("%s: line %u: group duplicated."),
@@ -1795,21 +1804,12 @@ static int pull_news (NNTP_Type *s, int marked_bodies) /*{{{*/
 
 /*}}}*/
 
-static int post_file (NNTP_Type *s, char *file) /*{{{*/
+/* a single attempt to post an already-open file over NNTP */
+static int post_file_nntp (NNTP_Type *s, char *file, FILE *fp) /*{{{*/
 {
-   FILE *fp;
    int status;
    char buf[8 * 1024];
 
-   log_message (_("Attempting to post %s..."), file);
-
-   fp = fopen (file, "r");
-   if (fp == NULL)
-     {
-	log_error (_("Unable to open file %s for posting."), file);
-	return -1;
-     }
-
    status = nntp_post_cmd (s);
    if (status != CONT_POST)
      {
@@ -1840,9 +1840,6 @@ static int post_file (NNTP_Type *s, char *file) /*{{{*/
 	     return -1;
 	  }
      }
-
-   fclose (fp);
-
    status = nntp_end_post (s);
    if (status == -1)
      {
@@ -1852,11 +1849,54 @@ static int post_file (NNTP_Type *s, char *file) /*{{{*/
 
    if (status != OK_POSTED)
      {
+	log_error (_("Article %s rejected. status = %d: %s."), file, status, s->rspbuf);
+
+	return -1;
+     }
+
+   return 0;
+}
+/*}}}*/
+
+static int post_file (NNTP_Type *s, char *file) /*{{{*/
+{
+   FILE *fp;
+   int status;
+   int retries = 0;
+
+   log_message (_("Attempting to post %s..."), file);
+
+   fp = fopen (file, "r");
+   if (fp == NULL)
+     {
+	/* this doesn't get a retry */
+	log_error (_("Unable to open file %s for posting."), file);
+	return -1;
+     }
+   /* some news servers will return a 436 if you try to post too soon
+    * after a session has started.
+    */
+   status = post_file_nntp (s, file, fp);
+   while (retries <= nntp_retries && 0 != status)
+     {
+       ++retries;
+
+       /* rewind the file to try again */
+       fseek(fp, 0, SEEK_SET);
+       slrn_sleep(nntp_retry_interval);
+       status = post_file_nntp (s, file, fp);
+     }
+
+   fclose(fp);
+
+   /* if status is -1, the posting failed (possibly multiple times) and
+    * we should move it to the rejects directory, then give up.
+    */
+   if (-1 == status)
+     {
 	char *name;
 	char bad_file [SLRN_MAX_PATH_LEN + 1];
 
-	log_error (_("Article %s rejected. status = %d: %s."), file, status, s->rspbuf);
-
 	name = slrn_basename (file);
 	if (-1 == slrn_dircat (Outgoing_Bad_Dir, name,
 			       bad_file, sizeof (bad_file)))