Subject: 28.0.50; Provide customization option for nnimap-keepalive-timer

From: Eric Abrahamsen <[email-masked]>
Date: Mon, 29 Mar 2021 09:22:40 -0700

Bob Newell requested the ability to customize the
`nnimap-keepalive-timer', and I've opened this bug report with a patch
that adds a new `nnimap-keepalive-times' customization option.

It lets you customize both function interval and period of inactivity,
or you can set it to nil to disable the keepalive altogether.

I also sneaked in a little extra change: since we provided the option to
use Dbus to close Gnus servers when your machine is going to sleep, I've
noticed that sometimes (more often than you'd think) I seem to be
sleeping the machine in between sending the keepalive NOOP and receiving
the response.

When the computer wakes, Emacs is hung while Gnus waits on an OK that
isn't coming, and I need to C-g to get out of it. I would have thought
this was a pretty small target to hit, particular since my imap servers
are all on this computer, but it happens quite often. So this patch also
lets `nnimap-streaming' to t around the keepalive command, so we don't
wait for the response. Semantically incorrect, but the effect is right.

If this is acceptable I can add a NEWS entry (and maybe the manual as
well?).

Eric

diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index 93e1c47be7..7017bf192e 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -156,6 +156,24 @@ nnimap-split-download-body
   :version "28.1"
   :type 'boolean)
 
+(defcustom nnimap-keepalive-times (cons (* 60 15)
+                                        (* 5 60))
+  "Configuration for the nnimap keepalive timer.
+The value is a cons of two integers (each representing a number
+of seconds): the first is how often to run the keepalive
+function, the second is the seconds of inactivity required to
+send the actual keepalive command.
+
+For example, the default (900 . 300) means to run the check every
+fifteen minutes and, if the user has been inactive for five
+minutes, send the keepalive command.
+
+Set to nil to disable keepalive commands altogether."
+  :version "28.1"
+  :type '(choice (const :tag "disable" nil)
+                 (cons (integer :tag "timer interval")
+                       (integer :tag "seconds of inactivity"))))
+
 (defvar nnimap--split-download-body nil
   "Like `nnimap-split-download-body', but for internal use.")
 
@@ -405,15 +423,16 @@ nnimap-credentials
       nil)))
 
 (defun nnimap-keepalive ()
-  (let ((now (current-time)))
+  (let ((now (current-time))
+        ;; Set this so we don't wait for a response.
+        (nnimap-streaming t))
     (dolist (buffer nnimap-process-buffers)
       (when (buffer-live-p buffer)
 	(with-current-buffer buffer
 	  (when (and nnimap-object
 		     (nnimap-last-command-time nnimap-object)
 		     (time-less-p
-		      ;; More than five minutes since the last command.
-		      (* 5 60)
+		      (cdr nnimap-keepalive-times)
 		      (time-subtract
 		       now
 		       (nnimap-last-command-time nnimap-object))))
@@ -447,8 +466,10 @@ nnimap-map-port
     port))
 
 (defun nnimap-open-connection-1 (buffer)
-  (unless nnimap-keepalive-timer
-    (setq nnimap-keepalive-timer (run-at-time (* 60 15) (* 60 15)
+  (unless (or nnimap-keepalive-timer
+              (null nnimap-keepalive-times))
+    (setq nnimap-keepalive-timer (run-at-time (car nnimap-keepalive-times)
+                                              (car nnimap-keepalive-times)
 					      #'nnimap-keepalive)))
   (with-current-buffer (nnimap-make-process-buffer buffer)
     (let* ((coding-system-for-read 'binary)