Merge branch 'master' of https://git.gnus.org/gnus
authorLars Ingebrigtsen <larsi@gnus.org>
Sun, 28 Dec 2014 13:51:38 +0000 (14:51 +0100)
committerLars Ingebrigtsen <larsi@gnus.org>
Sun, 28 Dec 2014 13:51:38 +0000 (14:51 +0100)
34 files changed:
lisp/ChangeLog
lisp/auth-source.el
lisp/gnus-art.el
lisp/gnus-bookmark.el
lisp/gnus-cloud.el
lisp/gnus-delay.el
lisp/gnus-fun.el
lisp/gnus-icalendar.el
lisp/gnus-notifications.el
lisp/gnus-registry.el
lisp/gnus-start.el
lisp/gnus-sum.el
lisp/gnus-util.el
lisp/gnus.el
lisp/ietf-drums.el
lisp/mailcap.el
lisp/message.el
lisp/mm-decode.el
lisp/mm-url.el
lisp/mm-util.el
lisp/mml.el
lisp/nnimap.el
lisp/nnweb.el
lisp/ntlm.el
lisp/parse-time.el
lisp/pop3.el
lisp/registry.el
lisp/tests/gnustest-registry.el
lisp/time-date.el
texi/ChangeLog
texi/auth.texi
texi/gnus-coding.texi
texi/gnus-faq.texi
texi/gnus.texi

index 2ff6817..786ee1b 100644 (file)
@@ -1,3 +1,286 @@
+2014-12-20  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * registry.el (cl-remf, cl-loop, cl-subseq):
+       Alias to remf, loop, and subseq respectively for old Emacsen.
+
+2014-12-18  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * registry.el (registry-db): Set default slot later.
+       This is because its value is not a literal integer.
+
+2014-12-18  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * registry.el (registry-db): Fix default registry-db max-size.
+
+2014-12-18  Stefan Monnier  <monnier@iro.umontreal.ca>
+
+       * mm-util.el (mm-with-unibyte-current-buffer): Mark obsolete and
+       add warning.
+
+       * gnus-art.el: Fix up compiler warnings.
+       (article-display-face, article-display-x-face): Remove unused `face'.
+       (gnus-article-browse-html-save-cid-content): Remove unused var `type'.
+       (article-date-ut): Remove unused var `first'.
+       (gnus-article-prepare): Remove unused var `gnus-article'.
+       (gnus-mime-save-part-and-strip): Remove unused var `param'.
+       (gnus-mime-inline-part): Remove unused vars `charset', `contents', and
+       `coding-system' along with corresponding dead code.
+       (gnus-mime-view-part-externally): Remove unused var
+       `mm-user-display-methods'.
+       (gnus-insert-mime-button): Let-bind gnus-tmp-id explicitly.
+       (gnus-display-mime): Remove unused var `handle'.
+       (gnus-mime-display-alternative): Remove unused var `props'.
+       (gnus-article-read-summary-keys): Remove unused var `up-to-top'.
+       (gnus-article-edit-done): Remove unused var `p'.
+       (gnus-url-mailto): Remove unused var `to'.
+       (gnus-treat-article): Let-bind gnus-treat-condition, part-number,
+       total-parts, and gnus-treat-type explicitly.  Remove unused var `elem'.
+
+2014-12-18  Eric Abrahamsen  <eric@ericabrahamsen.net>
+
+       * registry.el (registry-db): Consolidate the :max-hard and :max-soft
+       slots into a :max-size slot.
+       (registry-db-version): Add new variable for database version number.
+       (registry-prune): Use :max-size slot. Accept and use a sort-function
+       argument.
+       (registry-collect-prune-candidates): Add new function for finding
+       non-precious pruning candidates.
+       (registry-prune-hard-candidates, registry-prune-soft-candidates):
+       Remove obsolete functions.
+       (initialize-instance): Upgrade registry version when starting.
+
+       * gnus-registry.el (gnus-registry-prune-factor): Add new variable.
+       (gnus-registry-max-pruned-entries): Remove obsolete variable.
+       (gnus-registry-cache-file): Change default
+       filename extension to "eieio".
+       (gnus-registry-read): Add new function, split out from
+       `gnus-registry-load', that does the actual object reading.
+       (gnus-registry-load): Use it. Add condition case handler to check for
+       old filename extension and rename to the new one.
+       (gnus-registry-default-sort-function): New variable to specify a sort
+       function to use when pruning.
+       (gnus-registry-save, gnus-registry-insert): Use it.
+       (gnus-registry-sort-by-creation-time): Define a default sort function.
+
+       * tests/gnustest-registry.el (gnustest-registry-make-testable-db):
+       Adjust test for new object signature.
+       (gnustest-registry-pruning-test): Add new pruning test.
+       (gnustest-registry-sort-function): Default sort function for testing.
+       (gnustest-registry-pruning-sort-test): New test for sorting.
+
+2014-12-09  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-art.el (gnus-article-mime-handles): Refactored out into own
+       function for reuse.
+       (gnus-mime-buttonize-attachments-in-header): Adjusted.
+
+2014-12-07  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * message.el (message-change-subject): Really check whether the subject
+       changed.
+
+2014-12-05  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * mailcap.el (mailcap-mime-data): Add doc-view-mode as a viewer for
+       PDFs.
+       (mailcap-view-mime): New function.
+
+2014-12-01  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-cloud.el (gnus-cloud): Add :version tag.
+
+2014-11-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus-art.el (gnus-use-idna):
+       * gnus-sum.el (gnus-summary-idna-message):
+       * message.el (message-use-idna):
+       Protect against nil value for idna-program.
+
+       * message.el (message-use-idna): Load Mule-UCS for XEmacs 21.4.
+
+2014-11-26  John Mastro  <john.b.mastro@gmail.com>  (tiny change)
+
+       * auth-source.el (auth-source-macos-keychain-search-items): Return
+       result of `auth-source-macos-keychain-result-append' (bug#19074).
+
+2014-11-25  Glenn Morris  <rgm@gnu.org>
+
+       * gnus-start.el (gnus-save-newsrc-file-check-timestamp):
+       Add :version tag.
+
+2014-11-23  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * pop3.el (pop3-open-server): Warn unless encrypted.
+
+       * nnimap.el (nnimap-open-connection-1): Warn unless encrypted.
+
+2014-11-18  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Port new time stamp handling to Emacs 23.2.
+       This fix is for Gnus.  Problem reported by Katsumi Yamaoka.
+       * time-date.el (time-add, time-subtract, time-less-p):
+       Use eval-and-compile, not eval-when-compile.
+
+2014-11-17  Albert Krewinkel  <albert@zeitkraut.de>
+
+       * message.el (message-valid-fqdn-regexp): Add non-internaional new
+       TLDs.
+
+2014-11-17  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Port new time stamp handling to old Emacs and to XEmacs.
+       This is needed for Gnus, which copies time-date.el and which
+       runs on older Emacs implementations.
+       * time-date.el (with-decoded-time-value):
+       Handle 'nil' and floating-point arg more compatibly with new Emacs.
+       (encode-time-value, with-decoded-time-value):
+       Obsolete only if new Emacs.
+       (time-add, time-subtract, time-less-p): Define if not new Emacs.
+
+       Improve time stamp handling, and be more consistent about it.
+       This implements a suggestion made in:
+       http://lists.gnu.org/archive/html/emacs-devel/2014-10/msg00587.html
+       Among other things, this means timer.el no longer needs to
+       autoload the time-date module.
+       * time-date.el (seconds-to-time, days-to-time, time-since)
+       (with-decoded-time-value):
+       Treat 'nil' as current time.  This is mostly for XEmacs.
+       (encode-time-value, with-decoded-time-value): Obsolete.
+       (time-add, time-subtract, time-less-p): Use no-op autoloads, for
+       XEmacs.  Define only if XEmacs, as they're now C builtins in Emacs.
+
+2014-11-14  Lars Magne Ingebrigtsen  <larsi@gnus.org>
+
+       * gnus-sum.el (gnus-summary-exit-no-update): Don't query about
+       discarding changes in ephemeral groups.
+
+       * ietf-drums.el (ietf-drums-parse-address): Don't issue warnings about
+       things the user isn't interested in.
+
+2014-11-13  Julien Danjou  <jd@abydos>
+
+       * gnus-notifications.el (gnus-notifications-notify): Provide both
+       app-icon and image-path.
+
+2014-11-10  Kenjiro NAKAYAMA  <nakayamakenjiro@gmail.com>
+
+       * mm-url.el (mm-url-encode-multipart-form-data):
+       Restore to handle "multipart/form-data" by eww.
+
+2014-11-07  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus-start.el (gnus-activate-group): Fix typo reported by Tim
+       Landscheidt.
+
+2014-10-29  Paul Eggert  <eggert@cs.ucla.edu>
+
+       Simplify use of current-time and friends.
+       * gnus-delay.el (gnus-delay-article):
+       * gnus-sum.el (gnus-summary-read-document):
+       * gnus-util.el (gnus-seconds-today, gnus-seconds-month):
+       * message.el (message-make-expires-date):
+       Omit unnecessary call to current-time.
+       * gnus-util.el (gnus-float-time): Simplify to an alias because
+       time-to-seconds now behaves like float-time with respect to nil arg.
+       (gnus-seconds-year): Don't call current-time twice to get the current
+       time stamp, as this can lead to inconsistent results.
+       * time-date.el (time-to-seconds) [!float-time]:
+       Use current time if arg is nil, to be compatible with float-time.
+       (time-date--day-in-year): New function, with most of the guts of
+       the old time-to-day-in-year.
+       (time-to-day-in-year): Use it.
+       (time-to-days): Use it, to avoid decoding the same time stamp twice.
+
+2014-10-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-mode-line-buffer-identification):
+       Don't add image data for a non-graphic display (bug#18813).
+
+2014-10-24  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.el (gnus-mode-line-buffer-identification): Don't shadow
+       load-path, it blocks autoloading of find-image (bug#18813).
+
+2014-10-24  enami tsugutomo  <tsugutomo.enami@jp.sony.com>
+
+       * nnimap.el (nnimap-wait-for-response): Ignore NOOP response requested
+       to keep connection open (bug#18728).
+
+2014-10-20  Glenn Morris  <rgm@gnu.org>
+
+       * Merge in all changes up to 24.4 release.
+
+2014-10-15  Jorge A. Alfaro-Murillo  <jorge.alfaro-murillo@yale.edu>  (tiny change)
+
+       * message.el (message-insert-signature): Use `newline' instead of
+       inserting explicit "\n".
+
+2014-10-15  Sylvain Chouleur  <sylvain.chouleur@gmail.com>
+
+       * gnus-icalendar.el: Support vcal format timezones.
+       (gnus-icalendar-event--decode-datefield): Use icalendar functions to
+       compute dates with associated timezone.
+       (gnus-icalendar-event-from-ical): Compute all timezones.
+
+2014-10-14  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * gnus-start.el (gnus-save-newsrc-file-check-timestamp): New option to
+       check the newsrc.eld file's timestamp before saving it.
+       (gnus-save-newsrc-file): Use it, with a prompt when the newsrc.eld
+       timestamp has changed to be newer.
+
+2014-10-06  Jan Tatarik  <jan.tatarik@gmail.com>
+
+       * gnus-icalendar.el (gnus-icalendar-identities):
+       Include message-alternative-emails.
+
+2014-10-05  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * ntlm.el (ntlm-string-make-unibyte, ntlm-secure-hash):
+       New compatibility functions.
+       (ntlm-build-auth-response): Use them.
+
+2014-10-04  Thomas Fitzsimmons  <fitzsim@fitzsim.org>
+
+       * ntlm.el (ntlm-build-auth-request):
+       Add NTLM2 Session support.  (Bug#15603)
+
+2014-10-04  Alan Schmitt  <alan.schmitt@polytechnique.org>  (tiny change)
+
+       * nnimap.el (nnimap-process-expiry-targets): Reverse the list of
+       expired messages only when it was built in reverse order.
+
+2014-10-04  Peter Münster  <pmlists@free.fr>  (tiny change)
+
+       * gnus-delay.el (gnus-delay-send-queue): Remove `gnus-delay-header'
+       last so it can be used in `message-send-hook'.
+
+2014-09-29  Daiki Ueno  <ueno@gnu.org>
+
+       * mml.el (mml-parse-1): Error out if unknown mode is specified in
+       <#secure> tag (bug#18513).
+
+2014-09-27  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * parse-time.el: Require cl when compiling.
+
+2014-09-26  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       Use cl-lib as much as possible following the 2014-09-26 change
+       in the Emacs trunk.
+       * parse-time.el: Try requiring cl-lib.
+       (parse-time-incf): Alias to cl-incf or incf.
+       (digit-char-p): Remove.
+       (parse-time-integer): Alias to cl-parse-integer or the one defined.
+       (parse-integer): Rename to parse-time-integer.
+       (parse-time-tokenize, parse-time-rules, parse-time-string)
+       Use parse-time-incf and parse-time-integer.
+
+2014-09-11  Paul Eggert  <eggert@cs.ucla.edu>
+
+       * gnus-cloud.el (gnus-cloud-parse-version-1): Fix misspelling
+       of ":delete".
+
 2014-08-26  Katsumi Yamaoka  <yamaoka@jpl.org>
 
        * gnus-art.el (gnus-article-browse-html-save-cid-content)
        * gnus-icalendar.el (gnus-icalendar-event:org-timestamp): Fix
        org-timestamp for events ending at midnight.
 
-2013-11-21  Ivan Shmakov  <ivan@siamics.net>  (tiny change)
+2013-11-21  Ivan Shmakov  <ivan@siamics.net>
 
        * nndoc.el (nndoc-type-alist, nndoc-debbugs-db-type-p): Support debbugs
        .log files.
 
        * gnus-group.el: Require gnus-sum and autoload functions to
        resolve warnings when gnus-group.el compiled alone.
-       (gnus-group-line-format): Documented new %F.
+       (gnus-group-line-format): Document new %F.
        (size of Fetched data) group line format; identifies disk space
        used by agent and cache.
-       (gnus-group-line-format-alist): Defined new F format.
+       (gnus-group-line-format-alist): Define new F format.
        (gnus-total-fetched-for): New function.
        (gnus-group-delete-group): No longer update
        gnus-cache-active-altered as gnus-request-delete-group now keeps
index 2b48c0c..0216dee 100644 (file)
@@ -1797,29 +1797,29 @@ entries for git.gnus.org:
         (while (not (eobp))
           (cond
            ((looking-at "^password: \"\\(.+\\)\"$")
-            (auth-source-macos-keychain-result-append
-             ret
-             keychain-generic
-             "secret"
-             (lexical-let ((v (match-string 1)))
-               (lambda () v))))
+            (setq ret (auth-source-macos-keychain-result-append
+                       ret
+                       keychain-generic
+                       "secret"
+                       (lexical-let ((v (match-string 1)))
+                         (lambda () v)))))
            ;; TODO: check if this is really the label
            ;; match 0x00000007 <blob>="AppleID"
            ((looking-at "^[ ]+0x00000007 <blob>=\"\\(.+\\)\"")
-            (auth-source-macos-keychain-result-append
-             ret
-             keychain-generic
-             "label"
-             (match-string 1)))
+            (setq ret (auth-source-macos-keychain-result-append
+                       ret
+                       keychain-generic
+                       "label"
+                       (match-string 1))))
            ;; match "crtr"<uint32>="aapl"
            ;; match "svce"<blob>="AppleID"
            ((looking-at "^[ ]+\"\\([a-z]+\\)\"[^=]+=\"\\(.+\\)\"")
-            (auth-source-macos-keychain-result-append
-             ret
-             keychain-generic
-             (match-string 1)
-             (match-string 2))))
-            (forward-line)))
+            (setq ret (auth-source-macos-keychain-result-append
+                       ret
+                       keychain-generic
+                       (match-string 1)
+                       (match-string 2)))))
+          (forward-line)))
       ;; return `ret' iff it has the :secret key
       (and (plist-get ret :secret) (list ret))))
 
index d55c703..aa041aa 100644 (file)
@@ -1627,8 +1627,11 @@ It is a string, such as \"PGP\". If nil, ask user."
   :type 'string
   :group 'mime-security)
 
+(defvar idna-program)
+
 (defcustom gnus-use-idna (and (condition-case nil (require 'idna) (file-error))
                              (mm-coding-system-p 'utf-8)
+                             idna-program
                              (executable-find idna-program))
   "Whether IDNA decoding of headers is used when viewing messages.
 This requires GNU Libidn, and by default only enabled if it is found."
@@ -1841,7 +1844,7 @@ Initialized from `text-mode-syntax-table.")
        (incf i)))
       i))
 
-(defun article-hide-headers (&optional arg delete)
+(defun article-hide-headers (&optional _arg _delete)
   "Hide unwanted headers and possibly sort them as well."
   (interactive)
   ;; This function might be inhibited.
@@ -2411,7 +2414,7 @@ long lines if and only if arg is positive."
       (if (and wash-face-p (memq 'face gnus-article-wash-types))
          (gnus-delete-images 'face)
        (let ((from (message-fetch-field "from"))
-             face faces)
+             faces)
          (save-current-buffer
            (when (and wash-face-p
                       (gnus-buffer-live-p gnus-original-article-buffer)
@@ -2461,7 +2464,7 @@ long lines if and only if arg is positive."
          (gnus-delete-images 'xface)
        ;; Display X-Faces.
        (let ((from (message-fetch-field "from"))
-             x-faces face)
+             x-faces)
          (save-current-buffer
            (when (and wash-face-p
                       (gnus-buffer-live-p gnus-original-article-buffer)
@@ -2794,7 +2797,7 @@ summary buffer."
   "Find CID content in HANDLES and save it in a file in DIRECTORY.
 Return file name."
   (save-match-data
-    (let (file type)
+    (let (file)
       (catch 'found
        (dolist (handle handles)
          (cond
@@ -3082,7 +3085,7 @@ images if any to the browser, and deletes them when exiting the group
        (gnus-summary-show-article)))))
 
 (defun article-hide-list-identifiers ()
-  "Remove list identifies from the Subject header.
+  "Remove list identifiers from the Subject header.
 The `gnus-list-identifiers' variable specifies what to do."
   (interactive)
   (let ((inhibit-point-motion-hooks t)
@@ -3396,7 +3399,7 @@ means show, 0 means toggle."
        'hidden
       nil)))
 
-(defun gnus-article-show-hidden-text (type &optional dummy)
+(defun gnus-article-show-hidden-text (type &optional _dummy)
   "Show all hidden text of type TYPE.
 Originally it is hide instead of DUMMY."
   (let ((inhibit-read-only t)
@@ -3435,7 +3438,7 @@ lines forward."
                     gnus-article-date-headers)
                   t))
 
-(defun article-date-ut (&optional type highlight date-position)
+(defun article-date-ut (&optional type _highlight date-position)
   "Convert DATE date to TYPE in the current article.
 The default type is `ut'.  See `gnus-article-date-headers' for
 possible values."
@@ -3443,7 +3446,6 @@ possible values."
   (let* ((case-fold-search t)
         (inhibit-read-only t)
         (inhibit-point-motion-hooks t)
-        (first t)
         (visible-date (mail-fetch-field "Date"))
         pos date bface eface)
     (save-excursion
@@ -3982,7 +3984,7 @@ This format is defined by the `gnus-article-time-format' variable."
       (set dir-var (file-name-directory result)))
     result))
 
-(defun gnus-article-archive-name (group)
+(defun gnus-article-archive-name (_group)
   "Return the first instance of an \"Archive-name\" in the current buffer."
   (let ((case-fold-search t))
     (when (re-search-forward "archive-name: *\\([^ \n\t]+\\)[ \t]*$" nil t)
@@ -4214,7 +4216,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
        default
       (or last-file default))))
 
-(defun gnus-plain-save-name (newsgroup headers &optional last-file)
+(defun gnus-plain-save-name (newsgroup _headers &optional last-file)
   "Generate file name from NEWSGROUP, HEADERS, and optional LAST-FILE.
 If variable `gnus-use-long-file-name' is non-nil, it is
 ~/News/news.group.  Otherwise, it is like ~/News/news/group/news."
@@ -4227,7 +4229,7 @@ If variable `gnus-use-long-file-name' is non-nil, it is
          default-directory))
        gnus-article-save-directory)))
 
-(defun gnus-sender-save-name (newsgroup headers &optional last-file)
+(defun gnus-sender-save-name (_newsgroup headers &optional _last-file)
   "Generate file name from sender."
   (let ((from (mail-header-from headers)))
     (expand-file-name
@@ -4424,6 +4426,8 @@ If variable `gnus-use-long-file-name' is non-nil, it is
 (substitute-key-definition
  'undefined 'gnus-article-read-summary-keys gnus-article-mode-map)
 
+(defvar gnus-article-send-map)
+
 (gnus-define-keys (gnus-article-send-map "S" gnus-article-mode-map)
   "W" gnus-article-wide-reply-with-original)
 (if (featurep 'xemacs)
@@ -4607,18 +4611,19 @@ commands:
           (forward-line line)
           (point)))))))
 
-(defun gnus-article-prepare (article &optional all-headers header)
+(defvar gnus-tmp-internal-hook)
+
+(defun gnus-article-prepare (article &optional all-headers _header)
   "Prepare ARTICLE in article mode buffer.
 ARTICLE should either be an article number or a Message-ID.
 If ARTICLE is an id, HEADER should be the article headers.
 If ALL-HEADERS is non-nil, no headers are hidden."
-  (save-excursion
+  (save-excursion                ;FIXME: Shouldn't that be save-current-buffer?
     ;; Make sure we start in a summary buffer.
     (unless (derived-mode-p 'gnus-summary-mode)
       (set-buffer gnus-summary-buffer))
     (setq gnus-summary-buffer (current-buffer))
-    (let* ((gnus-article (if header (mail-header-number header) article))
-          (summary-buffer (current-buffer))
+    (let* ((summary-buffer (current-buffer))
           (gnus-tmp-internal-hook gnus-article-internal-prepare-hook)
           (group gnus-newsgroup-name)
           result)
@@ -4717,6 +4722,8 @@ If ALL-HEADERS is non-nil, no headers are hidden."
            (gnus-run-hooks 'gnus-article-prepare-hook)
            t))))))
 
+(defvar gnus-mime-display-attachment-buttons-in-header)
+
 ;;;###autoload
 (defun gnus-article-prepare-display ()
   "Make the current buffer look like a nice article."
@@ -4840,6 +4847,16 @@ Valid specifiers include:
 General format specifiers can also be used.  See Info node
 `(gnus)Formatting Variables'.")
 
+(defvar gnus-tmp-type)
+(defvar gnus-tmp-type-long)
+(defvar gnus-tmp-name)
+(defvar gnus-tmp-description)
+(defvar gnus-tmp-id)
+(defvar gnus-tmp-length)
+(defvar gnus-tmp-dots)
+(defvar gnus-tmp-info)
+(defvar gnus-tmp-pressed-details)
+
 (defvar gnus-mime-button-line-format-alist
   '((?t gnus-tmp-type ?s)
     (?T gnus-tmp-type-long ?s)
@@ -5066,7 +5083,6 @@ If FILE is given, use it for the external part."
 The current article has a complicated MIME structure, giving up..."))
   (let* ((data (get-text-property (point) 'gnus-data))
         (id (get-text-property (point) 'gnus-part))
-        param
         (handles gnus-article-mime-handles))
     (unless file
       (setq file
@@ -5324,7 +5340,7 @@ Compressed files like .gz and .bz2 are decompressed."
                    (text-property-any (point-min) (point) 'gnus-data handle)))
            (setq handle (get-text-property b 'gnus-data))
            b))
-        start contents charset coding-system)
+        start)
     (when handle
       (when (= b (prog1
                     btn
@@ -5335,27 +5351,11 @@ Compressed files like .gz and .bz2 are decompressed."
        (setq b btn))
       (if (and (not arg) (mm-handle-undisplayer handle))
          (mm-remove-part handle)
-       (mm-with-unibyte-buffer
-         (mm-insert-part handle)
-         (setq contents
-               (or (mm-decompress-buffer (mm-handle-filename handle) nil t)
-                   (buffer-string))))
        (cond
-        ((not arg)
-         (unless (setq charset (mail-content-type-get
-                                (mm-handle-type handle) 'charset))
-           (unless (setq coding-system
-                         (mm-with-unibyte-buffer
-                           (insert contents)
-                           (mm-find-buffer-file-coding-system)))
-             (setq charset gnus-newsgroup-charset))))
+        ((not arg) nil)
         ((numberp arg)
          (if (mm-handle-undisplayer handle)
-             (mm-remove-part handle))
-         (setq charset
-               (or (cdr (assq arg
-                              gnus-summary-show-article-charset-alist))
-                   (mm-read-coding-system "Charset: "))))
+             (mm-remove-part handle)))
         ((mm-handle-undisplayer handle)
          (mm-remove-part handle)))
        (goto-char start)
@@ -5465,7 +5465,6 @@ specified charset."
   (interactive)
   (gnus-article-check-buffer)
   (let* ((handle (or handle (get-text-property (point) 'gnus-data)))
-        (mm-user-display-methods nil)
         (mm-inlined-types nil)
         (mail-parse-charset gnus-newsgroup-charset)
         (mail-parse-ignored-charsets
@@ -5833,11 +5832,12 @@ all parts."
     (when gnus-break-pages
       (gnus-narrow-to-page))))
 
-(defun gnus-insert-mime-button (handle gnus-tmp-id &optional displayed)
+(defun gnus-insert-mime-button (handle id &optional displayed)
   (let ((gnus-tmp-name
         (or (mm-handle-filename handle)
             (mail-content-type-get (mm-handle-type handle) 'url)
             ""))
+        (gnus-tmp-id id)
        (gnus-tmp-type (mm-handle-media-type handle))
        (gnus-tmp-description (or (mm-handle-description handle) ""))
        (gnus-tmp-dots
@@ -5888,7 +5888,7 @@ all parts."
            "hide" "show")
        (aref gnus-down-mouse-3 0))))))
 
-(defun gnus-widget-press-button (elems el)
+(defun gnus-widget-press-button (elems _el)
   (goto-char (widget-get elems :from))
   (gnus-article-press-button))
 
@@ -5906,8 +5906,7 @@ all parts."
          ;; may change the point.  So we set the window point.
          (set-window-point window point)))
       (let ((handles ihandles)
-           (inhibit-read-only t)
-           handle)
+           (inhibit-read-only t))
        (cond (handles)
              ((setq handles (mm-dissect-buffer nil gnus-article-loose-mime))
               (when gnus-article-emulate-mime
@@ -5984,7 +5983,7 @@ Since MIME attachments tend to be put at the end of an article, we may
 overlook them if there is a huge body.  This option offers you a copy
 of all non-inlinable MIME parts as buttons shown in front of an article.
 If nil, don't show those extra buttons."
-  :version "24.5"
+  :version "25.1"
   :group 'gnus-article-mime
   :type 'boolean)
 
@@ -6139,7 +6138,7 @@ If nil, don't show those extra buttons."
   (let* ((preferred (or preferred (mm-preferred-alternative handles)))
         (ihandles handles)
         (point (point))
-        handle (inhibit-read-only t) from props begend not-pref)
+        handle (inhibit-read-only t) from begend not-pref)
     (save-window-excursion
       (save-restriction
        (when ibegend
@@ -6335,6 +6334,40 @@ Provided for backwards compatibility."
     (when image
       (gnus-add-image 'shr image))))
 
+(defun gnus-article-mime-handles (&optional alist id all)
+  (if alist
+      (let ((i 1) newid flat)
+       (dolist (handle alist flat)
+         (setq newid (append id (list i))
+               i (1+ i))
+         (if (stringp (car handle))
+             (setq flat (nconc flat (gnus-article-mime-handles
+                                     (cdr handle) newid all)))
+           (delq (rassq handle all) all)
+           (setq flat (nconc flat (list (cons newid handle)))))))
+    (let ((flat (list nil)))
+      ;; Assume that elements of `gnus-article-mime-handle-alist'
+      ;; are in the decreasing order, but unnumbered subsidiaries
+      ;; in each element are in the increasing order.
+      (dolist (handle (reverse gnus-article-mime-handle-alist))
+       (if (stringp (cadr handle))
+           (setq flat (nconc flat (gnus-article-mime-handles
+                                   (cddr handle) (list (car handle)) flat)))
+         (delq (rassq (cdr handle) flat) flat)
+         (setq flat (nconc flat (list (cons (list (car handle))
+                                            (cdr handle)))))))
+      (setq flat (cdr flat))
+      (mapc (lambda (handle)
+             (if (cdar handle)
+                 ;; This is a hidden (i.e. unnumbered) handle.
+                 (progn
+                   (setcar handle
+                           (1+ (caar gnus-article-mime-handle-alist)))
+                   (push handle gnus-article-mime-handle-alist))
+               (setcar handle (caar handle))))
+           flat)
+      flat)))
+
 (defun gnus-mime-buttonize-attachments-in-header (&optional interactive)
   "Show attachments as buttons in the end of the header of an article.
 This function toggles the display when called interactively.  Note that
@@ -6342,108 +6375,70 @@ buttons to be added to the header are only the ones that aren't inlined
 in the body.  Use `gnus-header-face-alist' to highlight buttons."
   (interactive (list t))
   (gnus-with-article-buffer
-    (gmm-labels
-       ;; Function that returns a flattened version of
-       ;; `gnus-article-mime-handle-alist'.
-       ((flattened-alist
-         (&optional alist id all)
-         (if alist
-             (let ((i 1) newid flat)
-               (dolist (handle alist flat)
-                 (setq newid (append id (list i))
-                       i (1+ i))
-                 (if (stringp (car handle))
-                     (setq flat (nconc flat (flattened-alist (cdr handle)
-                                                             newid all)))
-                   (delq (rassq handle all) all)
-                   (setq flat (nconc flat (list (cons newid handle)))))))
-           (let ((flat (list nil)))
-             ;; Assume that elements of `gnus-article-mime-handle-alist'
-             ;; are in the decreasing order, but unnumbered subsidiaries
-             ;; in each element are in the increasing order.
-             (dolist (handle (reverse gnus-article-mime-handle-alist))
-               (if (stringp (cadr handle))
-                   (setq flat (nconc flat (flattened-alist (cddr handle)
-                                                           (list (car handle))
-                                                           flat)))
-                 (delq (rassq (cdr handle) flat) flat)
-                 (setq flat (nconc flat (list (cons (list (car handle))
-                                                    (cdr handle)))))))
-             (setq flat (cdr flat))
-             (mapc (lambda (handle)
-                     (if (cdar handle)
-                         ;; This is a hidden (i.e. unnumbered) handle.
-                         (progn
-                           (setcar handle
-                                   (1+ (caar gnus-article-mime-handle-alist)))
-                           (push handle gnus-article-mime-handle-alist))
-                       (setcar handle (caar handle))))
-                   flat)
-             flat))))
-      (let ((case-fold-search t) buttons handle type st)
-       (save-excursion
-         (save-restriction
-           (widen)
-           (article-narrow-to-head)
-           ;; Header buttons exist?
-           (while (and (not buttons)
-                       (re-search-forward "^attachments?:[\n ]+" nil t))
-             (when (get-char-property (match-end 0)
-                                      'gnus-button-attachment-extra)
-               (setq buttons (match-beginning 0))))
-           (widen)
+    (let ((case-fold-search t) buttons handle type st)
+      (save-excursion
+       (save-restriction
+         (widen)
+         (article-narrow-to-head)
+         ;; Header buttons exist?
+         (while (and (not buttons)
+                     (re-search-forward "^attachments?:[\n ]+" nil t))
+           (when (get-char-property (match-end 0)
+                                    'gnus-button-attachment-extra)
+             (setq buttons (match-beginning 0))))
+         (widen)
+         (when buttons
+           ;; Delete header buttons.
+           (delete-region buttons (if (re-search-forward "^[^ ]" nil t)
+                                      (match-beginning 0)
+                                    (point-max))))
+         (unless (and interactive buttons)
+           ;; Find buttons.
+           (setq buttons nil)
+           (dolist (button (gnus-article-mime-handles))
+             (setq handle (cdr button)
+                   type (mm-handle-media-type handle))
+             (when (or (and (if (gnus-buffer-live-p gnus-summary-buffer)
+                                (with-current-buffer gnus-summary-buffer
+                                  gnus-inhibit-images)
+                              gnus-inhibit-images)
+                            (string-match "\\`image/" type))
+                       (mm-inline-override-p handle)
+                       (and (mm-handle-disposition handle)
+                            (not (equal (car (mm-handle-disposition handle))
+                                        "inline"))
+                            (not (mm-attachment-override-p handle)))
+                       (not (mm-automatic-display-p handle))
+                       (not (or (and (mm-inlinable-p handle)
+                                     (mm-inlined-p handle))
+                                (mm-automatic-external-display-p type))))
+               (push button buttons)))
            (when buttons
-             ;; Delete header buttons.
-             (delete-region buttons (if (re-search-forward "^[^ ]" nil t)
-                                        (match-beginning 0)
-                                      (point-max))))
-           (unless (and interactive buttons)
-             ;; Find buttons.
-             (setq buttons nil)
-             (dolist (button (flattened-alist))
-               (setq handle (cdr button)
-                     type (mm-handle-media-type handle))
-               (when (or (and (if (gnus-buffer-live-p gnus-summary-buffer)
-                                  (with-current-buffer gnus-summary-buffer
-                                    gnus-inhibit-images)
-                                gnus-inhibit-images)
-                              (string-match "\\`image/" type))
-                         (mm-inline-override-p handle)
-                         (and (mm-handle-disposition handle)
-                              (not (equal (car (mm-handle-disposition handle))
-                                          "inline"))
-                              (not (mm-attachment-override-p handle)))
-                         (not (mm-automatic-display-p handle))
-                         (not (or (and (mm-inlinable-p handle)
-                                       (mm-inlined-p handle))
-                                  (mm-automatic-external-display-p type))))
-                 (push button buttons)))
-             (when buttons
-               ;; Add header buttons.
-               (article-goto-body)
-               (forward-line -1)
-               (narrow-to-region (point) (point))
-               (insert "Attachment" (if (cdr buttons) "s" "") ":")
-               (dolist (button (nreverse buttons))
-                 (setq st (point))
-                 (insert " ")
-                 (mm-handle-set-undisplayer
-                  (setq handle (copy-sequence (cdr button))) nil)
-                 (gnus-insert-mime-button handle (car button))
-                 (skip-chars-backward "\t\n ")
-                 (delete-region (point) (point-max))
-                 (when (> (current-column) (window-width))
-                   (goto-char st)
-                   (insert "\n")
-                   (end-of-line)))
-               (insert "\n")
-               (dolist (ovl (gnus-overlays-in (point-min) (point)))
-                 (gnus-overlay-put ovl 'gnus-button-attachment-extra t)
-                 (gnus-overlay-put ovl 'face nil))
-               (let ((gnus-treatment-function-alist
-                      '((gnus-treat-highlight-headers
-                         gnus-article-highlight-headers))))
-                 (gnus-treat-article 'head))))))))))
+             ;; Add header buttons.
+             (article-goto-body)
+             (forward-line -1)
+             (narrow-to-region (point) (point))
+             (insert "Attachment" (if (cdr buttons) "s" "") ":")
+             (dolist (button (nreverse buttons))
+               (setq st (point))
+               (insert " ")
+               (mm-handle-set-undisplayer
+                (setq handle (copy-sequence (cdr button))) nil)
+               (gnus-insert-mime-button handle (car button))
+               (skip-chars-backward "\t\n ")
+               (delete-region (point) (point-max))
+               (when (> (current-column) (window-width))
+                 (goto-char st)
+                 (insert "\n")
+                 (end-of-line)))
+             (insert "\n")
+             (dolist (ovl (gnus-overlays-in (point-min) (point)))
+               (gnus-overlay-put ovl 'gnus-button-attachment-extra t)
+               (gnus-overlay-put ovl 'face nil))
+             (let ((gnus-treatment-function-alist
+                    '((gnus-treat-highlight-headers
+                       gnus-article-highlight-headers))))
+               (gnus-treat-article 'head)))))))))
 
 ;;; Article savers.
 
@@ -6630,6 +6625,8 @@ specifies."
                      (if header-line-format 1 0)
                      2)))))))
 
+(defvar scroll-in-place)
+
 (defun gnus-article-next-page-1 (lines)
   (condition-case ()
       (let ((scroll-in-place nil)
@@ -6717,7 +6714,9 @@ not have a face in `gnus-article-boring-faces'."
   (unless (derived-mode-p 'gnus-article-mode)
     (error "Command invoked outside of a Gnus article buffer")))
 
-(defun gnus-article-read-summary-keys (&optional arg key not-restore-window)
+(defvar gnus-pick-mode)
+
+(defun gnus-article-read-summary-keys (&optional _arg key not-restore-window)
   "Read a summary buffer key sequence and execute it from the article buffer."
   (interactive "P")
   (gnus-article-check-buffer)
@@ -6730,8 +6729,6 @@ not have a face in `gnus-article-boring-faces'."
           "An" "Ap" [?A (meta return)] [?A delete]))
        (nosave-in-article
         '("AS" "\C-d"))
-       (up-to-top
-        '("n" "Gn" "p" "Gp"))
        keys new-sum-point)
     (with-current-buffer gnus-article-current-summary
       (let (gnus-pick-mode)
@@ -6890,6 +6887,7 @@ KEY is a string or a vector."
 (defvar gnus-agent-summary-mode)
 (defvar gnus-draft-mode)
 (defvar help-xref-stack-item)
+(defvar help-xref-following)
 
 (defun gnus-article-describe-bindings (&optional prefix)
   "Show a list of all defined keys, and their definitions.
@@ -7334,7 +7332,6 @@ groups."
   (let ((func gnus-article-edit-done-function)
        (buf (current-buffer))
        (start (window-start))
-       (p (point))
        (winconf gnus-prev-winconf))
     (widen) ;; Widen it in case that users narrowed the buffer.
     (funcall func arg)
@@ -7963,7 +7960,7 @@ do the highlighting.  See the documentation for those functions."
   (gnus-article-add-buttons)
   (gnus-article-add-buttons-to-head))
 
-(defun gnus-article-highlight-some (&optional force)
+(defun gnus-article-highlight-some (&optional _force)
   "Highlight current article.
 This function calls `gnus-article-highlight-headers',
 `gnus-article-highlight-signature', and `gnus-article-add-buttons' to
@@ -8266,9 +8263,11 @@ url is put as the `gnus-button-url' overlay property on the button."
        (error "Unknown news URL syntax"))))
     (list scheme server port group message-id articles)))
 
+(defvar nntp-port-number)
+
 (defun gnus-button-handle-news (url)
   "Fetch a news URL."
-  (destructuring-bind (scheme server port group message-id articles)
+  (destructuring-bind (_scheme server port group message-id _articles)
       (gnus-parse-news-url url)
     (cond
      (message-id
@@ -8390,7 +8389,7 @@ url is put as the `gnus-button-url' overlay property on the button."
   (with-current-buffer gnus-summary-buffer
     (gnus-summary-refer-article message-id)))
 
-(defun gnus-button-fetch-group (address &rest ignore)
+(defun gnus-button-fetch-group (address &rest _ignore)
   "Fetch GROUP specified by ADDRESS."
   (when (string-match "\\`\\(nntp\\|news\\):\\(//\\)?\\(.*\\)\\'"
                      address)
@@ -8438,15 +8437,15 @@ url is put as the `gnus-button-url' overlay property on the button."
   (setq url (replace-regexp-in-string "\n" " " url))
   (when (string-match "mailto:/*\\(.*\\)" url)
     (setq url (substring url (match-beginning 1) nil)))
-  (let (to args subject func)
-    (setq args (gnus-url-parse-query-string
+  (let* ((args (gnus-url-parse-query-string
                (if (string-match "^\\?" url)
                    (substring url 1)
                  (if (string-match "^\\([^?]+\\)\\?\\(.*\\)" url)
                      (concat "to=" (match-string 1 url) "&"
                              (match-string 2 url))
-                   (concat "to=" url))))
-         subject (cdr-safe (assoc "subject" args)))
+                   (concat "to=" url)))))
+         (subject (cdr-safe (assoc "subject" args)))
+         func)
     (gnus-msg-mail)
     (while args
       (setq func (intern-soft (concat "message-goto-" (downcase (caar args)))))
@@ -8503,7 +8502,7 @@ url is put as the `gnus-button-url' overlay property on the button."
      :action 'gnus-button-prev-page
      :button-keymap gnus-prev-page-map)))
 
-(defun gnus-button-next-page (&optional args more-args)
+(defun gnus-button-next-page (&optional _args _more-args)
   "Go to the next page."
   (interactive)
   (let ((win (selected-window)))
@@ -8511,7 +8510,7 @@ url is put as the `gnus-button-url' overlay property on the button."
     (gnus-article-next-page)
     (select-window win)))
 
-(defun gnus-button-prev-page (&optional args more-args)
+(defun gnus-button-prev-page (&optional _args _more-args)
   "Go to the prev page."
   (interactive)
   (let ((win (selected-window)))
@@ -8539,7 +8538,7 @@ url is put as the `gnus-button-url' overlay property on the button."
      :action 'gnus-button-next-page
      :button-keymap gnus-next-page-map)))
 
-(defun gnus-article-button-next-page (arg)
+(defun gnus-article-button-next-page (_arg)
   "Go to the next page."
   (interactive "P")
   (let ((win (selected-window)))
@@ -8547,7 +8546,7 @@ url is put as the `gnus-button-url' overlay property on the button."
     (gnus-article-next-page)
     (select-window win)))
 
-(defun gnus-article-button-prev-page (arg)
+(defun gnus-article-button-prev-page (_arg)
   "Go to the prev page."
   (interactive "P")
   (let ((win (selected-window)))
@@ -8598,20 +8597,31 @@ For example:
 
 (defvar gnus-inhibit-article-treatments nil)
 
-(defun gnus-treat-article (gnus-treat-condition
-                          &optional part-number total-parts gnus-treat-type)
-  (let ((gnus-treat-length (- (point-max) (point-min)))
+;; Dynamic variables.
+(defvar part-number)                    ;FIXME: Lacks a "gnus-" prefix.
+(defvar total-parts)                    ;FIXME: Lacks a "gnus-" prefix.
+(defvar gnus-treat-type)
+(defvar gnus-treat-condition)
+(defvar gnus-treat-length)
+
+(defun gnus-treat-article (condition
+                          &optional part-num total type)
+  (let ((gnus-treat-condition condition)
+        (part-number part-num)
+        (total-parts total)
+        (gnus-treat-type type)
+        (gnus-treat-length (- (point-max) (point-min)))
        (alist gnus-treatment-function-alist)
        (article-goto-body-goes-to-point-min-p t)
        (treated-type
-        (or (not gnus-treat-type)
+        (or (not type)
             (catch 'found
               (let ((list gnus-article-treat-types))
                 (while list
-                  (when (string-match (pop list) gnus-treat-type)
+                  (when (string-match (pop list) type)
                     (throw 'found t)))))))
        (highlightp (gnus-visual-p 'article-highlight 'highlight))
-       val elem)
+       val)
     (gnus-run-hooks 'gnus-part-display-hook)
     (dolist (elem alist)
       (setq val
@@ -8629,13 +8639,6 @@ For example:
        (save-restriction
          (funcall (cadr elem)))))))
 
-;; Dynamic variables.
-(defvar part-number)
-(defvar total-parts)
-(defvar gnus-treat-type)
-(defvar gnus-treat-condition)
-(defvar gnus-treat-length)
-
 (defun gnus-treat-predicate (val)
   (cond
    ((null val)
@@ -8884,7 +8887,7 @@ For example:
        (gnus-mime-security-show-details handle)
       (gnus-mime-security-verify-or-decrypt handle))))
 
-(defun gnus-insert-mime-security-button (handle &optional displayed)
+(defun gnus-insert-mime-security-button (handle &optional _displayed)
   (let* ((protocol (mm-handle-multipart-ctl-parameter handle 'protocol))
         (gnus-tmp-type
          (concat
@@ -8932,7 +8935,7 @@ For example:
      :action 'gnus-widget-press-button
      :button-keymap gnus-mime-security-button-map
      :help-echo
-     (lambda (widget)
+     (lambda (_widget)
        ;; Needed to properly clear the message due to a bug in
        ;; wid-edit (XEmacs only).
        (when (boundp 'help-echo-owns-message)
index 91d5c76..e5d218e 100644 (file)
@@ -251,7 +251,7 @@ So the cdr of each bookmark is an alist too.")
   (interactive)
   (save-excursion
     (save-window-excursion
-      ;; Avoir warnings?
+      ;; Avoid warnings?
       ;; (message "Saving Gnus bookmarks to file %s..." gnus-bookmark-default-file)
       (set-buffer (get-buffer-create  " *Gnus bookmarks*"))
       (erase-buffer)
index 8acea09..a42bcc0 100644 (file)
@@ -30,6 +30,7 @@
 
 (defgroup gnus-cloud nil
   "Syncing Gnus data via IMAP."
+  :version "25.1"
   :group 'gnus)
 
 (defcustom gnus-cloud-synced-files
@@ -39,6 +40,7 @@
     (:directory "~/News" :match ".*.SCORE\\'"))
   "List of file regexps that should be kept up-to-date via the cloud."
   :group 'gnus-cloud
+  ;; FIXME this type does not match the default.  Nor does the documentation.
   :type '(repeat regexp))
 
 (defvar gnus-cloud-group-name "*Emacs Cloud*")
        (let ((spec (ignore-errors (read (current-buffer))))
              length)
          (when (and (consp spec)
-                    (memq (plist-get spec :type) '(:file :data :deleta)))
+                    (memq (plist-get spec :type) '(:file :data :delete)))
            (setq length (plist-get spec :length))
            (push (append spec
                          (list
index 5432d4d..2a286da 100644 (file)
@@ -98,7 +98,7 @@ DELAY is a string, giving the length of the time.  Possible values are:
           (setq hour   (string-to-number (match-string 1 delay))
                 minute (string-to-number (match-string 2 delay)))
           ;; Use current time, except...
-          (setq deadline (apply 'vector (decode-time (current-time))))
+          (setq deadline (apply 'vector (decode-time)))
           ;; ... for minute and hour.
           (aset deadline 1 minute)
           (aset deadline 2 hour)
@@ -153,7 +153,7 @@ DELAY is a string, giving the length of the time.  Possible values are:
       (when (gnus-group-entry group)
        (gnus-activate-group group)
        (add-hook 'message-send-hook
-                 (lambda () (message-remove-header gnus-delay-header)))
+                 (lambda () (message-remove-header gnus-delay-header)) t)
        (setq articles (nndraft-articles))
        (while (setq article (pop articles))
          (gnus-request-head article group)
index e0d1578..8d08cd6 100644 (file)
 
 (defcustom gnus-x-face-omit-files nil
   "Regexp to match faces in `gnus-x-face-directory' to be omitted."
-  :version "24.5"
+  :version "25.1"
   :group 'gnus-fun
   :type 'string)
 
 (defcustom gnus-face-directory (expand-file-name "faces" gnus-directory)
   "*Directory where Face PNG files are stored."
-  :version "24.5"
+  :version "25.1"
   :group 'gnus-fun
   :type 'directory)
 
 (defcustom gnus-face-omit-files nil
   "Regexp to match faces in `gnus-face-directory' to be omitted."
-  :version "24.5"
+  :version "25.1"
   :group 'gnus-fun
   :type 'string)
 
@@ -239,7 +239,7 @@ Files matching `gnus-face-omit-files' are not considered."
 
 ;;;###autoload
 (defun gnus-insert-random-face-header ()
-  "Insert a randome Face header from `gnus-face-directory'."
+  "Insert a random Face header from `gnus-face-directory'."
   (gnus--insert-random-face-with-type 'gnus-random-face 'Face))
 
 (defface gnus-x-face '((t (:foreground "black" :background "white")))
index 9027c53..a9e4a24 100644 (file)
 (defmethod gnus-icalendar-event:start ((event gnus-icalendar-event))
   (format-time-string "%Y-%m-%d %H:%M" (gnus-icalendar-event:start-time event)))
 
-(defun gnus-icalendar-event--decode-datefield (ical field)
-  (let* ((date (icalendar--get-event-property ical field))
-         (date-props (icalendar--get-event-property-attributes ical field))
-         (tz (plist-get date-props 'TZID)))
-
-    (date-to-time (timezone-make-date-arpa-standard date nil tz))))
+(defun gnus-icalendar-event--decode-datefield (event field zone-map)
+  (let* ((dtdate (icalendar--get-event-property event field))
+         (dtdate-zone (icalendar--find-time-zone
+                       (icalendar--get-event-property-attributes
+                        event field) zone-map))
+         (dtdate-dec (icalendar--decode-isodatetime dtdate nil dtdate-zone)))
+    (apply 'encode-time dtdate-dec)))
 
 (defun gnus-icalendar-event--find-attendee (ical name-or-email)
   (let* ((event (car (icalendar--all-events ical)))
                               ("REQ-PARTICIPANT" 'required)
                               ("OPT-PARTICIPANT" 'optional)
                               (_                 'non-participant)))
+         (zone-map (icalendar--convert-all-timezones ical))
          (args (list :method method
                      :organizer organizer
-                     :start-time (gnus-icalendar-event--decode-datefield event 'DTSTART)
-                     :end-time (gnus-icalendar-event--decode-datefield event 'DTEND)
+                     :start-time (gnus-icalendar-event--decode-datefield event 'DTSTART zone-map)
+                     :end-time (gnus-icalendar-event--decode-datefield event 'DTEND zone-map)
                      :rsvp (string= (plist-get (cadr attendee) 'RSVP) "TRUE")
                      :participation-type participation-type
                      :req-participants (car attendee-names)
@@ -676,8 +678,9 @@ Gnus will only offer you the Accept/Tentative/Decline buttons for
 calendar events if any of your identities matches at least one
 RSVP participant.
 
-Your identity is guessed automatically from the variables `user-full-name',
-`user-mail-address', and `gnus-ignored-from-addresses'.
+Your identity is guessed automatically from the variables
+`user-full-name', `user-mail-address',
+`gnus-ignored-from-addresses' and `message-alternative-emails'.
 
 If you need even more aliases you can define them here.  It really
 only makes sense to define names or email addresses."
@@ -703,6 +706,7 @@ These will be used to retrieve the RSVP information from ical events."
                  (list user-full-name (regexp-quote user-mail-address)
                        ; NOTE: these can be lists
                        gnus-ignored-from-addresses ; already regexp-quoted
+                       message-alternative-emails  ;
                        (mapcar #'regexp-quote gnus-icalendar-additional-identities)))))
 
 ;; TODO: make the template customizable
index ee1083d..0729ea2 100644 (file)
@@ -92,9 +92,9 @@ Return a notification id if any, or t on success."
        :body subject
        :actions '("read" "Read")
        :on-action 'gnus-notifications-action
-       :app-icon (or photo-file
-                     (gnus-funcall-no-warning
-                      'image-search-load-path "gnus/gnus.png"))
+       :app-icon (gnus-funcall-no-warning
+                  'image-search-load-path "gnus/gnus.png")
+       :image-path photo-file
        :app-name "Gnus"
        :category "email.arrived"
        :timeout gnus-notifications-timeout)
index f3b81f7..92f8f04 100644 (file)
@@ -176,6 +176,7 @@ nnmairix groups are specifically excluded because they are ephemeral."
 (make-obsolete-variable 'gnus-registry-max-track-groups nil "23.4")
 (make-obsolete-variable 'gnus-registry-entry-caching nil "23.4")
 (make-obsolete-variable 'gnus-registry-trim-articles-without-groups nil "23.4")
+(make-obsolete-variable 'gnus-registry-max-pruned-entries nil "24.4")
 
 (defcustom gnus-registry-track-extra '(subject sender recipient)
   "Whether the registry should track extra data about a message.
@@ -231,7 +232,7 @@ the Bit Bucket."
 (defcustom gnus-registry-cache-file
   (nnheader-concat
    (or gnus-dribble-directory gnus-home-directory "~/")
-   ".gnus.registry.eioio")
+   ".gnus.registry.eieio")
   "File where the Gnus registry will be stored."
   :group 'gnus-registry
   :type 'file)
@@ -242,12 +243,38 @@ the Bit Bucket."
   :type '(radio (const :format "Unlimited " nil)
                 (integer :format "Maximum number: %v")))
 
-(defcustom gnus-registry-max-pruned-entries nil
-  "Maximum number of pruned entries in the registry, nil for unlimited."
-  :version "24.1"
+(defcustom gnus-registry-prune-factor 0.1
+  "When pruning, try to prune back to this factor less than the maximum size.
+
+In order to prevent constant pruning, we prune back to a number
+somewhat less than the maximum size.  This option controls
+exactly how much less.  For example, given a maximum size of
+50000 and a prune factor of 0.1, the pruning process will try to
+cut the registry back to \(- 50000 \(* 50000 0.1\)\) -> 45000
+entries.  The pruning process is constrained by the presence of
+\"precious\" entries."
+  :version "24.4"
   :group 'gnus-registry
-  :type '(radio (const :format "Unlimited " nil)
-                (integer :format "Maximum number: %v")))
+  :type 'float)
+
+(defcustom gnus-registry-default-sort-function
+  #'gnus-registry-sort-by-creation-time
+  "Sort function to use when pruning the registry.
+
+Entries which sort to the front of the list will be pruned
+first.
+
+This can slow pruning down.  Set to nil to perform no sorting."
+  :version "24.4"
+  :group 'gnus-registry
+  :type 'symbol)
+
+(defun gnus-registry-sort-by-creation-time (l r)
+  "Sort older entries to front of list."
+  ;; Pruning starts from the front of the list.
+  (time-less-p
+   (cadr (assq 'creation-time r))
+   (cadr (assq 'creation-time l))))
 
 (defun gnus-registry-fixup-registry (db)
   (when db
@@ -255,14 +282,12 @@ the Bit Bucket."
       (oset db :precious
             (append gnus-registry-extra-entries-precious
                     '()))
-      (oset db :max-hard
+      (oset db :max-size
             (or gnus-registry-max-entries
                 most-positive-fixnum))
       (oset db :prune-factor
-            0.1)
-      (oset db :max-soft
-            (or gnus-registry-max-pruned-entries
-                most-positive-fixnum))
+            (or gnus-registry-prune-factor
+               0.1))
       (oset db :tracked
             (append gnus-registry-track-extra
                     '(mark group keyword)))
@@ -278,8 +303,8 @@ the Bit Bucket."
     "Gnus Registry"
     :file (or file gnus-registry-cache-file)
     ;; these parameters are set in `gnus-registry-fixup-registry'
-    :max-hard most-positive-fixnum
-    :max-soft most-positive-fixnum
+    :max-size most-positive-fixnum
+    :version registry-db-version
     :precious nil
     :tracked nil)))
 
@@ -295,22 +320,27 @@ This is not required after changing `gnus-registry-cache-file'."
     (gnus-message 4 "Remaking the Gnus registry")
     (setq gnus-registry-db (gnus-registry-make-db))))
 
-(defun gnus-registry-read ()
-  "Read the registry cache file."
+(defun gnus-registry-load ()
+  "Load the registry from the cache file."
   (interactive)
   (let ((file gnus-registry-cache-file))
     (condition-case nil
-        (progn
-          (gnus-message 5 "Reading Gnus registry from %s..." file)
-          (setq gnus-registry-db
-               (gnus-registry-fixup-registry
-                (condition-case nil
-                    (with-no-warnings
-                      (eieio-persistent-read file 'registry-db))
-                  ;; Older EIEIO versions do not check the class name.
-                  ('wrong-number-of-arguments
-                   (eieio-persistent-read file)))))
-          (gnus-message 5 "Reading Gnus registry from %s...done" file))
+        (gnus-registry-read file)
+      (file-error
+       ;; Fix previous mis-naming of the registry file.
+       (let ((old-file-name
+             (concat (file-name-sans-extension
+                     gnus-registry-cache-file)
+                    ".eioio")))
+        (if (and (file-exists-p old-file-name)
+                 (yes-or-no-p
+                  (format "Rename registry file from %s to %s? "
+                          old-file-name file)))
+            (progn
+              (gnus-registry-read old-file-name)
+              (oset gnus-registry-db :file file)
+              (gnus-message 1 "Registry filename changed to %s" file))
+          (gnus-registry-remake-db t))))
       (error
        (gnus-message
         1
@@ -318,6 +348,19 @@ This is not required after changing `gnus-registry-cache-file'."
         file)
        (gnus-registry-remake-db t)))))
 
+(defun gnus-registry-read (file)
+  "Do the actual reading of the registry persistence file."
+  (gnus-message 5 "Reading Gnus registry from %s..." file)
+  (setq gnus-registry-db
+       (gnus-registry-fixup-registry
+        (condition-case nil
+            (with-no-warnings
+              (eieio-persistent-read file 'registry-db))
+          ;; Older EIEIO versions do not check the class name.
+          ('wrong-number-of-arguments
+           (eieio-persistent-read file)))))
+  (gnus-message 5 "Reading Gnus registry from %s...done" file))
+
 (defun gnus-registry-save (&optional file db)
   "Save the registry cache file."
   (interactive)
@@ -325,7 +368,8 @@ This is not required after changing `gnus-registry-cache-file'."
         (db (or db gnus-registry-db)))
     (gnus-message 5 "Saving Gnus registry (%d entries) to %s..."
                   (registry-size db) file)
-    (registry-prune db)
+    (registry-prune
+     db gnus-registry-default-sort-function)
     ;; TODO: call (gnus-string-remove-all-properties v) on all elements?
     (eieio-persistent-save db file)
     (gnus-message 5 "Saving Gnus registry (size %d) to %s...done"
@@ -1032,7 +1076,8 @@ only the last one's marks are returned."
   "Just like `registry-insert' but tries to prune on error."
   (when (registry-full db)
     (message "Trying to prune the registry because it's full")
-    (registry-prune db))
+    (registry-prune
+     db gnus-registry-default-sort-function))
   (registry-insert db id entry)
   entry)
 
@@ -1090,7 +1135,7 @@ only the last one's marks are returned."
   (gnus-message 5 "Initializing the registry")
   (gnus-registry-install-hooks)
   (gnus-registry-install-shortcuts)
-  (gnus-registry-read))
+  (gnus-registry-load))
 
 ;; FIXME: Why autoload this function?
 ;;;###autoload
@@ -1104,7 +1149,7 @@ only the last one's marks are returned."
   (add-hook 'nnmail-spool-hook 'gnus-registry-spool-action)
 
   (add-hook 'gnus-save-newsrc-hook 'gnus-registry-save)
-  (add-hook 'gnus-read-newsrc-el-hook 'gnus-registry-read)
+  (add-hook 'gnus-read-newsrc-el-hook 'gnus-registry-load)
 
   (add-hook 'gnus-summary-prepare-hook 'gnus-registry-register-message-ids))
 
@@ -1117,7 +1162,7 @@ only the last one's marks are returned."
   (remove-hook 'nnmail-spool-hook 'gnus-registry-spool-action)
 
   (remove-hook 'gnus-save-newsrc-hook 'gnus-registry-save)
-  (remove-hook 'gnus-read-newsrc-el-hook 'gnus-registry-read)
+  (remove-hook 'gnus-read-newsrc-el-hook 'gnus-registry-load)
 
   (remove-hook 'gnus-summary-prepare-hook 'gnus-registry-register-message-ids)
   (setq gnus-registry-enabled nil))
index 766e7c2..24c2b48 100644 (file)
@@ -442,6 +442,15 @@ See also `gnus-before-startup-hook'."
   :group 'gnus-newsrc
   :type 'hook)
 
+(defcustom gnus-save-newsrc-file-check-timestamp nil
+  "Check the modification time of the newsrc.eld file before saving it.
+When the newsrc.eld file is updated by multiple machines,
+checking the file's modification time is a good way to avoid
+overwriting updated data."
+  :version "25.1"
+  :group 'gnus-newsrc
+  :type 'boolean)
+
 (defcustom gnus-save-newsrc-hook nil
   "A hook called before saving any of the newsrc files."
   :group 'gnus-newsrc
@@ -1467,7 +1476,7 @@ newsgroup."
   "Check whether a group has been activated or not.
 If SCAN, request a scan of that group as well.  If METHOD, use
 that select method instead of determining the method based on the
-group name.  If DONT-CHECK, don't check check whether the group
+group name.  If DONT-CHECK, don't check whether the group
 actually exists.  If DONT-SUB-CHECK or DONT-CHECK, don't let the
 backend check whether the group actually exists."
   (let ((method (or method (inline (gnus-find-method-for-group group))))
@@ -2783,6 +2792,7 @@ If FORCE is non-nil, the .newsrc file is read."
       'msdos-long-file-names
       (lambda () t))))
 
+(defvar gnus-save-newsrc-file-last-timestamp nil)
 (defun gnus-save-newsrc-file (&optional force)
   "Save .newsrc file."
   ;; Note: We cannot save .newsrc file if all newsgroups are removed
@@ -2821,12 +2831,30 @@ If FORCE is non-nil, the .newsrc file is read."
          (erase-buffer)
           (gnus-message 5 "Saving %s.eld..." gnus-current-startup-file)
 
+          ;; check timestamp of `gnus-current-startup-file'.eld against
+          ;; `gnus-save-newsrc-file-last-timestamp'
+          (when gnus-save-newsrc-file-check-timestamp
+            (let* ((checkfile (concat gnus-current-startup-file ".eld"))
+                   (mtime (nth 5 (file-attributes checkfile))))
+              (when (and gnus-save-newsrc-file-last-timestamp
+                         (time-less-p gnus-save-newsrc-file-last-timestamp
+                                      mtime))
+                (unless (y-or-n-p
+                         (format "%s was updated externally after %s, save?"
+                                 checkfile
+                                 (format-time-string
+                                  "%c"
+                                  gnus-save-newsrc-file-last-timestamp)))
+                (error "Couldn't save %s: updated externally" checkfile)))))
+
           (if gnus-save-startup-file-via-temp-buffer
               (let ((coding-system-for-write gnus-ding-file-coding-system)
                     (standard-output (current-buffer)))
                 (gnus-gnus-to-quick-newsrc-format)
                 (gnus-run-hooks 'gnus-save-quick-newsrc-hook)
-                (save-buffer))
+                (save-buffer)
+                (setq gnus-save-newsrc-file-last-timestamp
+                            (nth 5 (file-attributes buffer-file-name))))
             (let ((coding-system-for-write gnus-ding-file-coding-system)
                   (version-control gnus-backup-startup-file)
                   (startup-file (concat gnus-current-startup-file ".eld"))
@@ -2861,7 +2889,9 @@ If FORCE is non-nil, the .newsrc file is read."
 
                       ;; Replace the existing startup file with the temp file.
                       (rename-file working-file startup-file t)
-                      (gnus-set-file-modes startup-file setmodes)))
+                      (gnus-set-file-modes startup-file setmodes)
+                      (setq gnus-save-newsrc-file-last-timestamp
+                            (nth 5 (file-attributes startup-file)))))
                 (condition-case nil
                     (delete-file working-file)
                   (file-error nil)))))
index db0242e..29f693f 100644 (file)
@@ -7334,6 +7334,7 @@ If FORCE (the prefix), also save the .newsrc file(s)."
         (gnus-group-is-exiting-without-update-p t)
         (quit-config (gnus-group-quit-config group)))
     (when (or no-questions
+             (gnus-ephemeral-group-p group)
              gnus-expert-user
              (gnus-y-or-n-p "Discard changes to this group and exit? "))
       (gnus-async-halt-prefetch)
@@ -9333,7 +9334,7 @@ Obeys the standard process/prefix convention."
      ((gnus-group-read-ephemeral-group
        (setq vgroup (format
                     "nnvirtual:%s-%s" gnus-newsgroup-name
-                    (format-time-string "%Y%m%dT%H%M%S" (current-time))))
+                    (format-time-string "%Y%m%dT%H%M%S")))
        `(nnvirtual ,vgroup (nnvirtual-component-groups ,groups))
        t
        (cons (current-buffer) 'summary)))
@@ -9869,6 +9870,7 @@ installed for this command to work."
   (if (not (and (condition-case nil (require 'idna)
                  (file-error))
                (mm-coding-system-p 'utf-8)
+               (symbol-value 'idna-program)
                (executable-find (symbol-value 'idna-program))))
       (gnus-message
        5 "GNU Libidn not installed properly (`idn' or `idna.el' missing)")
index fe4d707..526aa77 100644 (file)
@@ -313,14 +313,10 @@ Symbols are also allowed; their print names are used instead."
 
 ;; Every version of Emacs Gnus supports has built-in float-time.
 ;; The featurep test silences an irritating compiler warning.
-(eval-and-compile
+(defalias 'gnus-float-time
   (if (or (featurep 'emacs)
          (fboundp 'float-time))
-      (defalias 'gnus-float-time 'float-time)
-    (defun gnus-float-time (&optional time)
-      "Convert time value TIME to a floating point number.
-TIME defaults to the current time."
-      (time-to-seconds (or time (current-time))))))
+      'float-time 'time-to-seconds))
 
 ;;; Keymap macros.
 
@@ -389,19 +385,20 @@ TIME defaults to the current time."
 
 (defun gnus-seconds-today ()
   "Return the number of seconds passed today."
-  (let ((now (decode-time (current-time))))
+  (let ((now (decode-time)))
     (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600))))
 
 (defun gnus-seconds-month ()
   "Return the number of seconds passed this month."
-  (let ((now (decode-time (current-time))))
+  (let ((now (decode-time)))
     (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
        (* (- (car (nthcdr 3 now)) 1) 3600 24))))
 
 (defun gnus-seconds-year ()
   "Return the number of seconds passed this year."
-  (let ((now (decode-time (current-time)))
-       (days (format-time-string "%j" (current-time))))
+  (let* ((current (current-time))
+        (now (decode-time current))
+        (days (format-time-string "%j" current)))
     (+ (car now) (* (car (cdr now)) 60) (* (car (nthcdr 2 now)) 3600)
        (* (- (string-to-number days) 1) 3600 24))))
 
index 0cdb417..605882c 100644 (file)
@@ -326,8 +326,9 @@ be set in `.emacs' instead."
   (if (fboundp 'find-image)
       (defun gnus-mode-line-buffer-identification (line)
        (let ((str (car-safe line))
-             (load-path (mm-image-load-path)))
-         (if (and (stringp str)
+             (load-path (append (mm-image-load-path) load-path)))
+         (if (and (display-graphic-p)
+                  (stringp str)
                   (string-match "^Gnus:" str))
              (progn (add-text-properties
                      0 5
index 1121368..4fe8f18 100644 (file)
@@ -206,7 +206,6 @@ backslash and doublequote.")
                   (1+ (point))
                   (progn (forward-sexp 1) (1- (point))))))))
         (t
-         (message "Unknown symbol: %c" c)
          (forward-char 1))))
       ;; If we found no display-name, then we look for comments.
       (if display-name
index 4f1bdf4..1a1a992 100644 (file)
@@ -152,6 +152,10 @@ This is a compatibility function for different Emacsen."
       (non-viewer . t)
       (type   . "application/zip")
       ("copiousoutput"))
+     ("pdf"
+      (viewer . doc-view-mode)
+      (type . "application/pdf")
+      (test . (eq window-system 'x)))
      ("pdf"
       (viewer . "gv -safer %s")
       (type . "application/pdf")
@@ -1060,6 +1064,18 @@ If FORCE, re-parse even if already parsed."
                             common-mime-info)))))
     commands))
 
+(defun mailcap-view-mime (type)
+  "View the data in the current buffer that has MIME type TYPE.
+`mailcap-mime-data' determines the method to use."
+  (let ((method (mailcap-mime-info type)))
+    (if (stringp method)
+       (shell-command-on-region (point-min) (point-max)
+                                ;; Use stdin as the "%s".
+                                (format method "-")
+                                (current-buffer)
+                                t)
+      (funcall method))))
+
 (provide 'mailcap)
 
 ;;; mailcap.el ends here
index 424a56e..8fea926 100644 (file)
@@ -627,7 +627,7 @@ This may also be a list of regexps."
   "If non-nil, delete non-matching headers when forwarding a message.
 Only headers that match this regexp will be included.  This
 variable should be a regexp or a list of regexps."
-  :version "24.5"
+  :version "25.1"
   :group 'message-forwarding
   :type '(repeat :value-to-internal (lambda (widget value)
                                      (custom-split-regexp-maybe value))
@@ -1800,13 +1800,17 @@ no, only reply back to the author."
   :type '(radio (const :format "%v  " nil)
                (string :format "FQDN: %v")))
 
-(defcustom message-use-idna (and (condition-case nil (require 'idna)
-                                  (file-error))
-                                (mm-coding-system-p 'utf-8)
-                                (executable-find idna-program)
-                                (string= (idna-to-ascii "räksmörgås")
-                                         "xn--rksmrgs-5wao1o")
-                                t)
+(defcustom message-use-idna
+  (and (or (mm-coding-system-p 'utf-8)
+          (condition-case nil
+              (let (mucs-ignore-version-incompatibilities)
+                (require 'un-define))
+            (error)))
+       (condition-case nil (require 'idna) (file-error))
+       idna-program
+       (executable-find idna-program)
+       (string= (idna-to-ascii "räksmörgås") "xn--rksmrgs-5wao1o")
+       t)
   "Whether to encode non-ASCII in domain names into ASCII according to IDNA.
 GNU Libidn, and in particular the elisp package \"idna.el\" and
 the external program \"idn\", must be installed for this
@@ -1963,7 +1967,45 @@ You must have the \"hashcash\" binary installed, see `hashcash-path'."
          "cat\\|com\\|coop\\|edu\\|gov\\|"
          "info\\|int\\|jobs\\|"
          "mil\\|mobi\\|museum\\|name\\|net\\|"
-         "org\\|pro\\|tel\\|travel\\|uucp\\)")
+         "org\\|pro\\|tel\\|travel\\|uucp\\|"
+          ;; ICANN-era generic top-level domains
+          "academy\\|actor\\|agency\\|airforce\\|archi\\|associates\\|axa\\|"
+          "bar\\|bargains\\|bayern\\|beer\\|berlin\\|best\\|bid\\|bike\\|"
+          "biz\\|black\\|blackfriday\\|blue\\|boutique\\|build\\|builders\\|"
+          "buzz\\|cab\\|camera\\|camp\\|capital\\|cards\\|care\\|career\\|"
+          "careers\\|cash\\|catering\\|center\\|ceo\\|cheap\\|christmas\\|"
+          "church\\|citic\\|cleaning\\|clinic\\|clothing\\|club\\|codes\\|"
+          "coffee\\|college\\|cologne\\|com\\|community\\|company\\|computer\\|"
+          "construction\\|contractors\\|cooking\\|cool\\|country\\|creditcard\\|"
+          "cruises\\|dance\\|dating\\|democrat\\|dental\\|desi\\|design\\|"
+          "diamonds\\|directory\\|discount\\|domains\\|education\\|email\\|"
+          "engineering\\|enterprises\\|equipment\\|estate\\|eus\\|events\\|"
+          "exchange\\|expert\\|exposed\\|fail\\|farm\\|feedback\\|finance\\|"
+          "financial\\|fish\\|fishing\\|fitness\\|flights\\|florist\\|foo\\|"
+          "foundation\\|frogans\\|fund\\|furniture\\|futbol\\|gal\\|"
+          "gallery\\|gift\\|glass\\|globo\\|gmo\\|gop\\|graphics\\|gratis\\|"
+          "gripe\\|guide\\|guitars\\|guru\\|hamburg\\|haus\\|hiphop\\|"
+          "holdings\\|holiday\\|homes\\|horse\\|house\\|immobilien\\|"
+          "industries\\|info\\|ink\\|institute\\|insure\\|international\\|"
+          "investments\\|jetzt\\|juegos\\|kaufen\\|kim\\|kitchen\\|kiwi\\|"
+          "koeln\\|kred\\|land\\|lat\\|latino\\|lease\\|life\\|lighting\\|"
+          "limited\\|limo\\|link\\|loans\\|london\\|luxe\\|luxury\\|"
+          "management\\|mango\\|marketing\\|media\\|meet\\|menu\\|miami\\|"
+          "moda\\|moe\\|monash\\|moscow\\|motorcycles\\|nagoya\\|name\\|"
+          "net\\|neustar\\|ninja\\|nyc\\|okinawa\\|onl\\|org\\|paris\\|"
+          "partners\\|parts\\|photo\\|photography\\|photos\\|pics\\|"
+          "pictures\\|pink\\|plumbing\\|pro\\|productions\\|properties\\|"
+          "pub\\|qpon\\|quebec\\|recipes\\|red\\|reisen\\|ren\\|rentals\\|"
+          "repair\\|report\\|rest\\|reviews\\|rich\\|rocks\\|rodeo\\|"
+          "ruhr\\|ryukyu\\|saarland\\|schule\\|scot\\|services\\|sexy\\|"
+          "shiksha\\|shoes\\|singles\\|social\\|sohu\\|solar\\|solutions\\|"
+          "soy\\|supplies\\|supply\\|support\\|surgery\\|systems\\|tattoo\\|"
+          "tax\\|technology\\|tienda\\|tips\\|today\\|tokyo\\|tools\\|"
+          "town\\|toys\\|trade\\|training\\|university\\|uno\\|vacations\\|"
+          "vegas\\|ventures\\|viajes\\|villas\\|vision\\|vodka\\|vote\\|"
+          "voting\\|voto\\|voyage\\|wang\\|watch\\|webcam\\|wed\\|wien\\|"
+          "wiki\\|works\\|wtc\\|wtf\\|xyz\\|yachts\\|yokohama\\|you\\|"
+          "zone\\)")
   ;; http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
   ;; http://en.wikipedia.org/wiki/GTLD
   ;; `approved, but not yet in operation': .xxx
@@ -2308,7 +2350,7 @@ Leading \"Re: \" is not stripped by this function.  Use the function
                   ((not (string-match
                          (concat "^[ \t]*"
                                  (regexp-quote new-subject)
-                                 " \t]*$")
+                                 "[ \t]*$")
                          old-subject))  ; yes, it really is a new subject
                    ;; delete eventual Re: prefix
                    (setq old-subject
@@ -3575,15 +3617,16 @@ Message buffers and is not meant to be called directly."
       (goto-char (point-max))
       ;; Insert the signature.
       (unless (bolp)
-       (insert "\n"))
+       (newline))
       (when message-signature-insert-empty-line
-       (insert "\n"))
-      (insert "-- \n")
+       (newline))
+      (insert "-- ")
+      (newline)
       (if (eq signature t)
          (insert-file-contents signature-file)
        (insert signature))
       (goto-char (point-max))
-      (or (bolp) (insert "\n")))))
+      (or (bolp) (newline)))))
 
 (defun message-insert-importance-high ()
   "Insert header to mark message as important."
@@ -5593,7 +5636,7 @@ If NOW, use that time instead."
   "Make date string for the Expires header.  Expiry in DAYS days.
 
 In posting styles use `(\"Expires\" (make-expires-date 30))'."
-  (let* ((cur (decode-time (current-time)))
+  (let* ((cur (decode-time))
         (nday (+ days (nth 3 cur))))
     (setf (nth 3 cur) nday)
     (message-make-date (apply 'encode-time cur))))
index cde0af0..f5b4d7c 100644 (file)
@@ -647,7 +647,7 @@ MIME-Version header before proceeding."
          (unless from
            (setq from (mail-fetch-field "from")))
          ;; FIXME: In some circumstances, this code is running within
-         ;; an unibyte macro.  mail-extract-address-components
+         ;; a unibyte macro.  mail-extract-address-components
          ;; creates unibyte buffers. This `if', though not a perfect
          ;; solution, avoids most of them.
          (if from
index bb342d6..bbeb1d8 100644 (file)
@@ -414,13 +414,51 @@ spaces.  Die Die Die."
 
 (autoload 'mml-compute-boundary "mml")
 
+(defun mm-url-encode-multipart-form-data (pairs &optional boundary)
+  "Return PAIRS encoded in multipart/form-data."
+  ;; RFC1867
+  ;; Get a good boundary
+  (unless boundary
+    (setq boundary (mml-compute-boundary '())))
+  (concat
+   ;; Start with the boundary
+   "--" boundary "\r\n"
+   ;; Create name value pairs
+   (mapconcat
+    'identity
+    ;; Delete any returned items that are empty
+    (delq nil
+          (mapcar (lambda (data)
+                    (cond ((equal (car data) "file")
+                           ;; For each pair
+                           (format
+                            ;; Encode the name
+                            "Content-Disposition: form-data; name=%S; filename=%S\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: binary\r\n\r\n%s"
+                            (cdr (assoc "name" (cdr data))) (cdr (assoc "filename" (cdr data)))
+                            (cond ((stringp (cdr (assoc "filedata" (cdr data))))
+                                   (cdr (assoc "filedata" (cdr data))))
+                                  ((integerp (cdr (assoc "filedata" (cdr data))))
+                                   (number-to-string (cdr (assoc "filedata" (cdr data))))))))
+                          ((equal (car data) "submit")
+                           "Content-Disposition: form-data; name=\"submit\"\r\n\r\nSubmit\r\n")
+                          (t
+                           (format
+                            "Content-Disposition: form-data;name=%S\r\n\r\n%s\r\n"
+                            (car data) (concat (mm-url-form-encode-xwfu (cdr data)))
+                            ))))
+                  pairs))
+    ;; use the boundary as a separator
+    (concat "\r\n--" boundary "\r\n"))
+   ;; put a boundary at the end.
+   "--" boundary "--\r\n"))
+
 (defun mm-url-remove-markup ()
   "Remove all HTML markup, leaving just plain text."
   (goto-char (point-min))
   (while (search-forward "<!--" nil t)
     (delete-region (match-beginning 0)
-                  (or (search-forward "-->" nil t)
-                      (point-max))))
+                   (or (search-forward "-->" nil t)
+                       (point-max))))
   (goto-char (point-min))
   (while (re-search-forward "<[^>]+>" nil t)
     (replace-match "" t t)))
index 31b7d07..e40aece 100644 (file)
@@ -1243,6 +1243,7 @@ evaluating FORMS but it is no longer done.  So, some programs assuming
 it if any may malfunction."
   (if (featurep 'xemacs)
       `(progn ,@forms)
+    (message "Warning: Using brain-dead macro `mm-with-unibyte-current-buffer'!")
     (let ((multibyte (make-symbol "multibyte")))
       `(let ((,multibyte enable-multibyte-characters))
         (when ,multibyte
@@ -1253,6 +1254,7 @@ it if any may malfunction."
             (set-buffer-multibyte t)))))))
 (put 'mm-with-unibyte-current-buffer 'lisp-indent-function 0)
 (put 'mm-with-unibyte-current-buffer 'edebug-form-spec '(body))
+(make-obsolete 'mm-with-unibyte-current-buffer nil "25.1")
 
 (defun mm-find-charset-region (b e)
   "Return a list of Emacs charsets in the region B to E."
index 726faee..fccdf52 100644 (file)
@@ -257,7 +257,9 @@ part.  This is for the internal use, you should never modify the value.")
                ((string= mode "encrypt")
                 (setq tags (list "encrypt" method)))
                ((string= mode "signencrypt")
-                (setq tags (list "sign" method "encrypt" method))))
+                (setq tags (list "sign" method "encrypt" method)))
+               (t
+                (error "Unknown secure mode %s" mode)))
          (eval `(mml-insert-tag ,secure-mode
                                 ,@tags
                                 ,(if keyfile "keyfile")
index 1730bd4..45d10dd 100644 (file)
@@ -405,6 +405,7 @@ textual parts.")
               "*nnimap*" (current-buffer) nnimap-address
               (nnimap-map-port (car ports))
               :type nnimap-stream
+              :warn-unless-encrypted t
               :return-list t
               :shell-command nnimap-shell-program
               :capability-command "1 CAPABILITY\r\n"
@@ -986,10 +987,10 @@ textual parts.")
                    (setq target nil))
                (nnheader-message 7 "Expiring article %s:%d" group article))
              (when target
-               (push article deleted-articles))))))))
+               (push article deleted-articles))))))
+      (setq deleted-articles (nreverse deleted-articles))))
     ;; Change back to the current group again.
     (nnimap-change-group group server)
-    (setq deleted-articles (nreverse deleted-articles))
     (nnimap-delete-article (gnus-compress-sequence deleted-articles))
     deleted-articles))
 
@@ -1888,7 +1889,7 @@ Return the server's response to the SELECT or EXAMINE command."
                        (while (and (not (bobp))
                                    (progn
                                      (forward-line -1)
-                                     (looking-at "\\*"))))
+                                     (looking-at "\\*\\|[0-9]+ OK NOOP"))))
                        (not (looking-at (format "%d .*\n" sequence)))))
            (when messagep
              (nnheader-message-maybe
index e909372..6802484 100644 (file)
@@ -438,7 +438,7 @@ Valid types include `google', `dejanews', and `gmane'.")
   t)
 
 (defun nnweb-google-identity (url)
-  "Return an unique identifier based on URL."
+  "Return a unique identifier based on URL."
   (if (string-match "selm=\\([^ &>]+\\)" url)
       (match-string 1 url)
     url))
index bff3bab..ef6e020 100644 (file)
@@ -80,8 +80,8 @@ is not given."
        (request-msgType (concat (make-string 1 1) (make-string 3 0)))
                                        ;0x01 0x00 0x00 0x00
        (request-flags (concat (make-string 1 7) (make-string 1 178)
-                              (make-string 2 0)))
-                                       ;0x07 0xb2 0x00 0x00
+                              (make-string 1 8) (make-string 1 0)))
+                                       ;0x07 0xb2 0x08 0x00
        lu ld off-d off-u)
     (when (string-match "@" user)
       (unless domain
@@ -110,8 +110,46 @@ is not given."
   (defmacro ntlm-string-as-unibyte (string)
     (if (fboundp 'string-as-unibyte)
        `(string-as-unibyte ,string)
+      string))
+  (defmacro ntlm-string-make-unibyte (string)
+    (if (fboundp 'string-make-unibyte)
+       `(string-make-unibyte ,string)
       string)))
 
+(eval-and-compile
+  (autoload 'sha1 "sha1")
+  (if (fboundp 'secure-hash)
+      (defalias 'ntlm-secure-hash 'secure-hash)
+    (defun ntlm-secure-hash (algorithm object &optional start end binary)
+      "Return the secure hash of OBJECT, a buffer or string.
+ALGORITHM is a symbol specifying the hash to use: md5, sha1.
+
+The two optional arguments START and END are positions specifying for
+which part of OBJECT to compute the hash.  If nil or omitted, uses the
+whole OBJECT.
+
+If BINARY is non-nil, returns a string in binary form."
+      (cond ((eq algorithm 'md5)
+            (if binary
+                (let* ((hex (md5 object start end))
+                       (len (length hex))
+                       (beg 0)
+                       rest)
+                  (while (< beg len)
+                    (push (ntlm-string-make-unibyte
+                           (char-to-string
+                            (string-to-number
+                             (substring hex beg (setq beg (+ beg 2)))
+                             16)))
+                          rest))
+                  (apply #'concat (nreverse rest)))
+              (md5 object start end)))
+           ((eq algorithm 'sha1)
+            (sha1 object start end binary))
+           (t
+            (error "(ntlm-secure-hash) Unsupported algorithm: %s"
+                   algorithm))))))
+
 (defun ntlm-build-auth-response (challenge user password-hashes)
   "Return the response string to a challenge string CHALLENGE given by
 the NTLM based server for the user USER and the password hash list
@@ -144,11 +182,35 @@ by PASSWORD-HASHES.  PASSWORD-HASHES should be a return value of
       (setq domain (substring user (1+ (match-beginning 0))))
       (setq user (substring user 0 (match-beginning 0))))
 
-    ;; generate response data
-    (setq lmRespData
-         (ntlm-smb-owf-encrypt (car password-hashes) challengeData))
-    (setq ntRespData
-         (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))
+    ;; check if "negotiate NTLM2 key" flag is set in type 2 message
+    (if (not (zerop (logand (aref flags 2) 8)))
+       (let (randomString
+             sessionHash)
+         ;; generate NTLM2 session response data
+         (setq randomString (ntlm-string-make-unibyte
+                             (concat
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256))
+                              (make-string 1 (random 256)))))
+         (setq sessionHash (ntlm-secure-hash
+                            'md5 (concat challengeData randomString)
+                            nil nil t))
+         (setq sessionHash (substring sessionHash 0 8))
+
+         (setq lmRespData (concat randomString (make-string 16 0)))
+         (setq ntRespData (ntlm-smb-owf-encrypt
+                           (cadr password-hashes) sessionHash)))
+      (progn
+       ;; generate response data
+       (setq lmRespData
+             (ntlm-smb-owf-encrypt (car password-hashes) challengeData))
+       (setq ntRespData
+             (ntlm-smb-owf-encrypt (cadr password-hashes) challengeData))))
 
     ;; get offsets to fields to pack the response struct in a string
     (setq lu (length user))
index 85b8ef1..bbbf3d7 100644 (file)
 
 ;;; Code:
 
-(eval-when-compile (require 'cl))      ;and ah ain't kiddin' 'bout it
-
 (eval-and-compile
-  (when (featurep 'xemacs)
-    (defvar parse-time-syntax (make-vector 256 nil))))
-(defvar parse-time-digits (make-vector 256 nil))
+  (ignore-errors (require 'cl-lib)))
+(eval-when-compile
+  (require 'cl)                                ;and ah ain't kiddin' 'bout it
+  (defalias 'parse-time-incf (if (featurep 'cl-lib) 'cl-incf 'incf)))
 
 ;; Byte-compiler warnings
 (defvar parse-time-elt)
 (defvar parse-time-val)
 
-(unless (aref parse-time-digits ?0)
-  (loop for i from ?0 to ?9
-    do (aset parse-time-digits i (- i ?0))))
-
-(when (featurep 'xemacs)
-  (unless (aref parse-time-syntax ?0)
-    (loop for i from ?0 to ?9
-         do (aset parse-time-syntax i ?0))
-    (loop for i from ?A to ?Z
-         do (aset parse-time-syntax i ?A))
-    (loop for i from ?a to ?z
-         do (aset parse-time-syntax i ?a))
-    (aset parse-time-syntax ?+ 1)
-    (aset parse-time-syntax ?- -1)
-    (aset parse-time-syntax ?: ?d)))
-
-(defsubst digit-char-p (char)
-  (aref parse-time-digits char))
-
 (eval-and-compile
   (if (featurep 'xemacs)
-      (defsubst parse-time-string-chars (char)
-       (and (< char (length parse-time-syntax))
-            (aref parse-time-syntax char)))
+      (progn
+       (defvar parse-time-syntax (make-vector 256 nil))
+       (loop for i from ?0 to ?9
+             do (aset parse-time-syntax i ?0))
+       (loop for i from ?A to ?Z
+             do (aset parse-time-syntax i ?A))
+       (loop for i from ?a to ?z
+             do (aset parse-time-syntax i ?a))
+       (aset parse-time-syntax ?+ 1)
+       (aset parse-time-syntax ?- -1)
+       (aset parse-time-syntax ?: ?d)
+       (defsubst parse-time-string-chars (char)
+         (and (< char (length parse-time-syntax))
+              (aref parse-time-syntax char))))
     (defsubst parse-time-string-chars (char)
       (save-match-data
        (let (case-fold-search str)
                ((string-match "[[:lower:]]" str) ?a)
                ((string-match "[[:digit:]]" str) ?0)))))))
 
-(put 'parse-error 'error-conditions '(parse-error error))
-(put 'parse-error 'error-message "Parsing error")
-
-(defsubst parse-integer (string &optional start end)
-  "[CL] Parse and return the integer in STRING, or nil if none."
-  (let ((integer 0)
-       (digit 0)
-       (index (or start 0))
-       (end (or end (length string))))
-    (when (< index end)
-      (let ((sign (aref string index)))
-       (if (or (eq sign ?+) (eq sign ?-))
-           (setq sign (parse-time-string-chars sign)
-                 index (1+ index))
-         (setq sign 1))
-       (while (and (< index end)
-                   (setq digit (digit-char-p (aref string index))))
-         (setq integer (+ (* integer 10) digit)
-               index (1+ index)))
-       (if (/= index end)
-           (signal 'parse-error `("not an integer"
-                                  ,(substring string (or start 0) end)))
-         (* sign integer))))))
+(eval-and-compile
+  (if (fboundp 'cl-parse-integer)
+      (defalias 'parse-time-integer 'cl-parse-integer)
+    (defvar parse-time-digits (make-vector 256 nil))
+    (loop for i from ?0 to ?9
+         do (aset parse-time-digits i (- i ?0)))
+    (defun parse-time-integer (string &rest keys)
+      "[CL] Parse and return the integer in STRING, or nil if none."
+      (let* ((start (plist-get keys :start))
+            (end (or (plist-get keys :end) (length string)))
+            (integer 0)
+            (digit 0)
+            (index (or start 0)))
+       (when (< index end)
+         (let ((sign (aref string index)))
+           (if (or (eq sign ?+) (eq sign ?-))
+               (setq sign (parse-time-string-chars sign)
+                     index (1+ index))
+             (setq sign 1))
+           (while (and (< index end)
+                       (setq digit (aref parse-time-digits
+                                         (aref string index))))
+             (setq integer (+ (* integer 10) digit)
+                   index (1+ index)))
+           (if (/= index end)
+               (error "Not an integer string: `%s'" string)
+             (* sign integer))))))))
 
 (defun parse-time-tokenize (string)
   "Tokenize STRING into substrings."
     (while (< index end)
       (while (and (< index end)                ;Skip invalid characters.
                  (not (setq c (parse-time-string-chars (aref string index)))))
-       (incf index))
+       (parse-time-incf index))
       (setq start index all-digits (eq c ?0))
-      (while (and (< (incf index) end) ;Scan valid characters.
+      (while (and (< (parse-time-incf index) end) ;Scan valid characters.
                  (setq c (parse-time-string-chars (aref string index))))
        (setq all-digits (and all-digits (eq c ?0))))
       (if (<= index end)
-         (push (if all-digits (parse-integer string start index)
+         (push (if all-digits (parse-time-integer string
+                                                  :start start :end index)
                  (substring string start index))
                list)))
     (nreverse list)))
               (= 5 (length parse-time-elt))
               (or (= (aref parse-time-elt 0) ?+)
                   (= (aref parse-time-elt 0) ?-))))
-     ,#'(lambda () (* 60 (+ (parse-integer parse-time-elt 3 5)
-                           (* 60 (parse-integer parse-time-elt 1 3)))
+     ,#'(lambda () (* 60 (+ (parse-time-integer parse-time-elt :start 3 :end 5)
+                           (* 60 (parse-time-integer parse-time-elt
+                                                     :start 1 :end 3)))
                      (if (= (aref parse-time-elt 0) ?-) -1 1))))
     ((5 4 3)
      ,#'(lambda () (and (stringp parse-time-elt)
@@ -230,9 +227,10 @@ unknown are returned as nil."
                (let ((new-val (if rule
                                   (let ((this (pop rule)))
                                     (if (vectorp this)
-                                        (parse-integer
+                                        (parse-time-integer
                                          parse-time-elt
-                                         (aref this 0) (aref this 1))
+                                         :start (aref this 0)
+                                         :end (aref this 1))
                                       (funcall this)))
                                 parse-time-val)))
                  (rplaca (nthcdr (pop slots) time) new-val))))))))
index dfc646b..64a704f 100644 (file)
@@ -561,6 +561,7 @@ Returns the process associated with the connection."
                     'tls)
                    (t
                     (or pop3-stream-type 'network)))
+            :warn-unless-encrypted t
             :capability-command "CAPA\r\n"
             :end-of-command "^\\(-ERR\\|+OK\\).*\n"
             :end-of-capability "^\\.\r?\n\\|^-ERR"
index dbc7b51..ab1e37b 100644 (file)
 ;; This library provides a general-purpose EIEIO-based registry
 ;; database with persistence, initialized with these fields:
 
-;; version: a float, 0.1 currently (don't change it)
+;; version: a float
 
-;; max-hard: an integer, default 5000000
+;; max-size: an integer, default most-positive-fixnum
 
-;; max-soft: an integer, default 50000
+;; prune-factor: a float between 0 and 1, default 0.1
 
 ;; precious: a list of symbols
 
 ;; Note that whether a field has one or many pieces of data, the data
 ;; is always a list of values.
 
-;; The user decides which fields are "precious", F2 for example.  At
-;; PRUNE TIME (when the :prune-function is called), the registry will
-;; trim any entries without the F2 field until the size is :max-soft
-;; or less.  No entries with the F2 field will be removed at PRUNE
-;; TIME.
+;; The user decides which fields are "precious", F2 for example.  When
+;; the registry is pruned, any entries without the F2 field will be
+;; removed until the size is :max-size * :prune-factor _less_ than the
+;; maximum database size. No entries with the F2 field will be removed
+;; at PRUNE TIME, which means it may not be possible to prune back all
+;; the way to the target size.
 
-;; When an entry is inserted, the registry will reject new entries
-;; if they bring it over the max-hard limit, even if they have the F2
+;; When an entry is inserted, the registry will reject new entries if
+;; they bring it over the :max-size limit, even if they have the F2
 ;; field.
 
 ;; The user decides which fields are "tracked", F1 for example.  Any
       (error
        "eieio not found in `load-path' or gnus-fallback-lib/ directory.")))
 
+(eval-when-compile
+  (unless (fboundp 'cl-remf)
+    (defalias 'cl-remf 'remf)
+    (defalias 'cl-loop 'loop)
+    (defalias 'cl-subseq 'subseq)))
+
+;; The version number needs to be kept outside of the class definition
+;; itself.  The persistent-save process does *not* write to file any
+;; slot values that are equal to the default :initform value.  If a
+;; database object is at the most recent version, therefore, its
+;; version number will not be written to file.  That makes it
+;; difficult to know when a database needs to be upgraded.
+(defvar registry-db-version 0.2
+  "The current version of the registry format.")
+
 (defclass registry-db (eieio-persistent)
   ((version :initarg :version
-            :initform 0.1
-            :type float
-            :custom float
+            :initform nil
+            :type (or null float)
             :documentation "The registry version.")
-   (max-hard :initarg :max-hard
-             :initform 5000000
+   (max-size :initarg :max-size
+             ;; :initform most-positive-fixnum ;; see below
              :type integer
              :custom integer
-             :documentation "Never accept more than this many elements.")
-   (max-soft :initarg :max-soft
-             :initform 50000
-             :type integer
-             :custom integer
-             :documentation "Prune as much as possible to get to this size.")
+             :documentation "The maximum number of registry entries.")
    (prune-factor
     :initarg :prune-factor
     :initform 0.1
     :type float
     :custom float
-    :documentation "At the max-hard limit, prune size * this entries.")
+    :documentation "Prune to \(:max-size * :prune-factor\) less
+    than the :max-size limit.  Should be a float between 0 and 1.")
    (tracked :initarg :tracked
             :initform nil
             :type t
    (data :initarg :data
          :type hash-table
          :documentation "The data hashtable.")))
+;; Do this separately, since defclass doesn't allow expressions in :initform.
+(oset-default registry-db max-size most-positive-fixnum)
+
+(defmethod initialize-instance :BEFORE ((this registry-db) slots)
+  "Check whether a registry object needs to be upgraded."
+  ;; Hardcoded upgrade routines.  Version 0.1 to 0.2 requires the
+  ;; :max-soft slot to disappear, and the :max-hard slot to be renamed
+  ;; :max-size.
+  (let ((current-version
+        (and (plist-member slots :version)
+             (plist-get slots :version))))
+    (when (or (null current-version)
+             (eql current-version 0.1))
+      (setq slots
+           (plist-put slots :max-size (plist-get slots :max-hard)))
+      (setq slots
+           (plist-put slots :version registry-db-version))
+      (cl-remf slots :max-hard)
+      (cl-remf slots :max-soft))))
 
 (defmethod initialize-instance :AFTER ((this registry-db) slots)
   "Set value of data slot of THIS after initialization."
@@ -267,7 +297,7 @@ This is the key count of the :data slot."
 (defmethod registry-full ((db registry-db))
   "Checks if registry-db THIS is full."
   (>= (registry-size db)
-      (oref db :max-hard)))
+      (oref db :max-size)))
 
 (defmethod registry-insert ((db registry-db) key entry)
   "Insert ENTRY under KEY into the registry-db THIS.
@@ -279,7 +309,7 @@ Errors out if the key exists already."
 
   (assert (not (registry-full db))
          nil
-         "registry max-hard size limit reached")
+         "registry max-size limit reached")
 
   ;; store the entry
   (puthash key entry (oref db :data))
@@ -312,58 +342,51 @@ Errors out if the key exists already."
               (registry-lookup-secondary-value db tr val value-keys))))
         (oref db :data))))))
 
-(defmethod registry-prune ((db registry-db) &optional sortfun)
-  "Prunes the registry-db object THIS.
-Removes only entries without the :precious keys if it can,
-then removes oldest entries first.
-Returns the number of deleted entries.
-If SORTFUN is given, tries to keep entries that sort *higher*.
-SORTFUN is passed only the two keys so it must look them up directly."
-  (dolist (collector '(registry-prune-soft-candidates
-                      registry-prune-hard-candidates))
-    (let* ((size (registry-size db))
-          (collected (funcall collector db))
-          (limit (nth 0 collected))
-          (candidates (nth 1 collected))
-          ;; sort the candidates if SORTFUN was given
-          (candidates (if sortfun (sort candidates sortfun) candidates))
-          (candidates-count (length candidates))
-          ;; are we over max-soft?
-          (prune-needed (> size limit)))
-
-      ;; while we have more candidates than we need to remove...
-      (while (and (> candidates-count (- size limit)) candidates)
-       (decf candidates-count)
-       (setq candidates (cdr candidates)))
-
-      (registry-delete db candidates nil)
-      (length candidates))))
-
-(defmethod registry-prune-soft-candidates ((db registry-db))
-  "Collects pruning candidates from the registry-db object THIS.
-Proposes only entries without the :precious keys."
+(defmethod registry-prune ((db registry-db) &optional sortfunc)
+  "Prunes the registry-db object DB.
+
+Attempts to prune the number of entries down to \(*
+:max-size :prune-factor\) less than the max-size limit, so
+pruning doesn't need to happen on every save. Removes only
+entries without the :precious keys, so it may not be possible to
+reach the target limit.
+
+Entries to be pruned are first sorted using SORTFUNC.  Entries
+from the front of the list are deleted first.
+
+Returns the number of deleted entries."
+  (let ((size (registry-size db))
+       (target-size (- (oref db :max-size)
+                       (* (oref db :max-size)
+                          (oref db :prune-factor))))
+       candidates)
+    (if (> size target-size)
+       (progn
+         (setq candidates
+               (registry-collect-prune-candidates
+                db (- size target-size) sortfunc))
+         (length (registry-delete db candidates nil)))
+      0)))
+
+(defmethod registry-collect-prune-candidates ((db registry-db) limit sortfunc)
+  "Collects pruning candidates from the registry-db object DB.
+
+Proposes only entries without the :precious keys, and attempts to
+return LIMIT such candidates.  If SORTFUNC is provided, sort
+entries first and return candidates from beginning of list."
   (let* ((precious (oref db :precious))
         (precious-p (lambda (entry-key)
                       (cdr (memq (car entry-key) precious))))
         (data (oref db :data))
-        (limit (oref db :max-soft))
-        (candidates (loop for k being the hash-keys of data
-                          using (hash-values v)
-                          when (notany precious-p v)
-                          collect k)))
-    (list limit candidates)))
-
-(defmethod registry-prune-hard-candidates ((db registry-db))
-  "Collects pruning candidates from the registry-db object THIS.
-Proposes any entries over the max-hard limit minus size * prune-factor."
-  (let* ((data (oref db :data))
-        ;; prune to (size * prune-factor) below the max-hard limit so
-        ;; we're not pruning all the time
-        (limit (max 0 (- (oref db :max-hard)
-                         (* (registry-size db) (oref db :prune-factor)))))
-        (candidates (loop for k being the hash-keys of data
-                          collect k)))
-    (list limit candidates)))
+        (candidates (cl-loop for k being the hash-keys of data
+                             using (hash-values v)
+                             when (notany precious-p v)
+                             collect (cons k v))))
+    ;; We want the full entries for sorting, but should only return a
+    ;; list of entry keys.
+    (when sortfunc
+      (setq candidates (sort candidates sortfunc)))
+    (delq nil (cl-subseq (mapcar #'car candidates) 0 limit))))
 
 (provide 'registry)
 ;;; registry.el ends here
index 174a0cb..e6ac8db 100644 (file)
     (should-not (registry--match :member entry '((hello)))))
   (message "Done with matching testing."))
 
-(defun gnustest-registry-make-testable-db (n &optional name file)
+(defun gnustest-registry-sort-function (l r)
+  "Sort lower values of sort-field earlier."
+  (< (cadr (assq 'sort-field l))
+     (cadr (assq 'sort-field r))))
+
+(defun gnustest-registry-make-testable-db (n &optional prune-factor name file)
   (let* ((db (registry-db
               (or name "Testing")
               :file (or file "unused")
-              :max-hard n
-              :max-soft 0               ; keep nothing not precious
+              :max-size n
+             :prune-factor (or prune-factor 0.1)
               :precious '(extra more-extra)
               :tracked '(sender subject groups))))
     (dotimes (i n)
       (registry-insert db i `((sender "me")
                               (subject "about you")
-                              (more-extra) ; empty data key should be pruned
-                              ;; first 5 entries will NOT have this extra data
-                              ,@(when (< 5 i) (list (list 'extra "more data")))
+                              (more-extra) ; Empty data key should be pruned.
+                              ;; First 5 entries will NOT have this extra data.
+                              ,@(when (< 4 i) (list (list 'extra "more data")))
+                             (sort-field ,(- n i))
                               (groups ,(number-to-string i)))))
     db))
 
     (should (= n (length (registry-search db :all t))))
     (message "Secondary search after delete")
     (should (= n (length (registry-lookup-secondary-value db 'sender "me"))))
-    ;; (message "Pruning")
-    ;; (let* ((tokeep (registry-search db :member '((extra "more data"))))
-    ;;        (count (- n (length tokeep)))
-    ;;        (pruned (registry-prune db))
-    ;;        (prune-count (length pruned)))
-    ;;   (message "Expecting to prune %d entries and pruned %d"
-    ;;            count prune-count)
-    ;;   (should (and (= count 5)
-    ;;                (= count prune-count))))
     (message "Done with usage testing.")))
 
+(ert-deftest gnustest-registry-pruning-test ()
+  "Check that precious entries are never pruned."
+  (let ((dbs (list
+             ;; Can prune fully without touching precious entries.
+             (gnustest-registry-make-testable-db 10 0.1)
+             ;; Pruning limited by precious entries.
+             (gnustest-registry-make-testable-db 10 0.6))))
+    (dolist (db dbs)
+      (message "Pruning")
+      (let* ((size (registry-size db))
+            (limit (- (oref db :max-size)
+                      (* (oref db :max-size)
+                         (oref db :prune-factor))))
+            (keepers (registry-search db :member '((extra "more data"))))
+            (expected-prune-count (min (- size (length keepers))
+                                       (- size limit)))
+            (actual-prune-count (registry-prune db)))
+       (ert-info
+           ((format "Expected to prune %d entries but pruned %d"
+                    expected-prune-count actual-prune-count)
+            :prefix "Error: ")
+         (should (= expected-prune-count actual-prune-count)))))))
+
+(ert-deftest gnustest-registry-pruning-sort-test ()
+  "Check that entries are sorted properly before pruning."
+  (let ((db (gnustest-registry-make-testable-db 10 0.4))
+       ;; These entries have the highest 'sort-field values.  Pruning
+       ;; sorts by lowest values first, then prunes from the front of
+       ;; the list, so these entries survive
+       (expected-survivors '(5 6 7 8 9 0))
+       actual-survivors disjunct)
+    (registry-prune
+     db #'gnustest-registry-sort-function)
+    (maphash (lambda (k v) (push k actual-survivors))
+            (oref db :data))
+    (setq disjunct (cl-set-exclusive-or
+                   expected-survivors
+                   actual-survivors))
+    (ert-info
+       ((format "Incorrect pruning: %s" disjunct)
+        :prefix "Error: ")
+      (should (null disjunct)))))
+
 (ert-deftest gnustest-registry-persistence-test ()
   (let* ((n 100)
          (tempfile (make-temp-file "registry-persistence-"))
          (name "persistence tester")
-         (db (gnustest-registry-make-testable-db n name tempfile))
+         (db (gnustest-registry-make-testable-db n nil name tempfile))
          size back)
     (message "Saving to %s" tempfile)
     (eieio-persistent-save db)
     (should (= (registry-size back) n))
     (should (= (registry-size back) (registry-size db)))
     (delete-file tempfile)
-    (message "Pruning Gnus registry to 0 by setting :max-soft")
-    (oset db :max-soft 0)
+    (message "Pruning Gnus registry to 0 by setting :max-size")
+    (oset db :max-size 0)
     (registry-prune db)
     (should (= (registry-size db) 0)))
   (message "Done with Gnus registry usage testing."))
index 48fe229..e7a8cc7 100644 (file)
 ;; value equal to HIGH * 2^16 + LOW + USEC * 10^-6 + PSEC * 10^-12
 ;; seconds, where missing components are treated as zero.  HIGH can be
 ;; negative, either because the value is a time difference, or because
-;; the machine supports negative time stamps that fall before the epoch.
-;; The macro `with-decoded-time-value' and the function
-;; `encode-time-value' make it easier to deal with these formats.
-;; See `time-subtract' for an example of how to use them.
+;; it represents a time stamp before the epoch.  Typically, there are
+;; more time values than the underlying system time type supports,
+;; but the reverse can also be true.
 
 ;;; Code:
 
@@ -44,7 +43,7 @@ The value of the last form in BODY is returned.
 
 Each element of the list VARLIST is a list of the form
 \(HIGH-SYMBOL LOW-SYMBOL MICRO-SYMBOL [PICO-SYMBOL [TYPE-SYMBOL]] TIME-VALUE).
-The time value TIME-VALUE is decoded and the result it bound to
+The time value TIME-VALUE is decoded and the result is bound to
 the symbols HIGH-SYMBOL, LOW-SYMBOL and MICRO-SYMBOL.
 The optional PICO-SYMBOL is bound to the picoseconds part.
 
@@ -66,7 +65,32 @@ list (HIGH LOW MICRO PICO)."
                     (pop elt)))
             (time-value (car elt))
             (gensym (make-symbol "time")))
-       `(let* ,(append `((,gensym ,time-value)
+       `(let* ,(append `((,gensym (or ,time-value (current-time)))
+                         (,gensym
+                          (cond
+                           ((integerp ,gensym)
+                            (list (ash ,gensym -16)
+                                  (logand ,gensym 65535)))
+                           ((floatp ,gensym)
+                            (let* ((usec (* 1000000 (mod ,gensym 1)))
+                                   (ps (round (* 1000000 (mod usec 1))))
+                                   (us (floor usec))
+                                   (lo (floor (mod ,gensym 65536)))
+                                   (hi (floor ,gensym 65536)))
+                              (if (eq ps 1000000)
+                                  (progn
+                                    (setq ps 0)
+                                    (setq us (1+ us))
+                                    (if (eq us 1000000)
+                                        (progn
+                                          (setq us 0)
+                                          (setq lo (1+ lo))
+                                          (if (eq lo 65536)
+                                              (progn
+                                                (setq lo 0)
+                                                (setq hi (1+ hi))))))))
+                              (list hi lo us ps)))
+                           (t ,gensym)))
                          (,high (pop ,gensym))
                          ,low ,micro)
                        (when pico `(,pico))
@@ -108,6 +132,10 @@ it is assumed that PICO was omitted and should be treated as zero."
    ((eq type 3) (list high low micro pico))
    ((null type) (encode-time-value high low micro 0 pico))))
 
+(when (and (fboundp 'time-add) (subrp (symbol-function 'time-add)))
+  (make-obsolete 'encode-time-value nil "25.1")
+  (make-obsolete 'with-decoded-time-value nil "25.1"))
+
 (autoload 'parse-time-string "parse-time")
 (autoload 'timezone-make-date-arpa-standard "timezone")
 
@@ -147,56 +175,28 @@ If DATE lacks timezone information, GMT is assumed."
   (or (featurep 'emacs)
       (and (fboundp 'float-time)
            (subrp (symbol-function 'float-time)))
-      (defun time-to-seconds (time)
-        "Convert time value TIME to a floating point number."
-        (with-decoded-time-value ((high low micro pico type time))
-          (+ (* 1.0 high 65536)
+      (defun time-to-seconds (&optional time)
+        "Convert optional value TIME to a floating point number.
+TIME defaults to the current time."
+        (with-decoded-time-value ((high low micro pico type
+                                  (or time (current-time))))
+          (+ (* high 65536.0)
              low
             (/ (+ (* micro 1e6) pico) 1e12))))))
 
 ;;;###autoload
 (defun seconds-to-time (seconds)
-  "Convert SECONDS (a floating point number) to a time value."
-  (let* ((usec (* 1000000 (mod seconds 1)))
-        (ps (round (* 1000000 (mod usec 1))))
-        (us (floor usec))
-        (lo (floor (mod seconds 65536)))
-        (hi (floor seconds 65536)))
-    (if (eq ps 1000000)
-       (progn
-         (setq ps 0)
-         (setq us (1+ us))
-         (if (eq us 1000000)
-             (progn
-               (setq us 0)
-               (setq lo (1+ lo))
-               (if (eq lo 65536)
-                   (progn
-                     (setq lo 0)
-                     (setq hi (1+ hi))))))))
-    (list hi lo us ps)))
-
-;;;###autoload
-(defun time-less-p (t1 t2)
-  "Return non-nil if time value T1 is earlier than time value T2."
-  (with-decoded-time-value ((high1 low1 micro1 pico1 type1 t1)
-                           (high2 low2 micro2 pico2 type2 t2))
-    (or (< high1 high2)
-       (and (= high1 high2)
-            (or (< low1 low2)
-                (and (= low1 low2)
-                     (or (< micro1 micro2)
-                         (and (= micro1 micro2)
-                              (< pico1 pico2)))))))))
+  "Convert SECONDS to a time value."
+  (time-add 0 seconds))
 
 ;;;###autoload
 (defun days-to-time (days)
   "Convert DAYS into a time value."
-  (let* ((seconds (* 1.0 days 60 60 24))
-        (high (condition-case nil (floor (/ seconds 65536))
-                (range-error most-positive-fixnum))))
-    (list high (condition-case nil (floor (- seconds (* 1.0 high 65536)))
-                (range-error 65535)))))
+  (let ((time (condition-case nil (seconds-to-time (* 86400.0 days))
+               (range-error (list most-positive-fixnum 65535)))))
+    (if (integerp days)
+       (setcdr (cdr time) nil))
+    time))
 
 ;;;###autoload
 (defun time-since (time)
@@ -205,53 +205,71 @@ TIME should be either a time value or a date-time string."
   (when (stringp time)
     ;; Convert date strings to internal time.
     (setq time (date-to-time time)))
-  (time-subtract (current-time) time))
+  (time-subtract nil time))
 
 ;;;###autoload
 (defalias 'subtract-time 'time-subtract)
 
-;;;###autoload
-(defun time-subtract (t1 t2)
-  "Subtract two time values, T1 minus T2.
+;; These autoloads do nothing in Emacs 25, where the functions are builtin.
+;;;###autoload(autoload 'time-add "time-date")
+;;;###autoload(autoload 'time-subtract "time-date")
+;;;###autoload(autoload 'time-less-p "time-date")
+
+(eval-and-compile
+  (when (not (and (fboundp 'time-add) (subrp (symbol-function 'time-add))))
+
+    (defun time-add (t1 t2)
+      "Add two time values T1 and T2.  One should represent a time difference."
+      (with-decoded-time-value ((high low micro pico type t1)
+                               (high2 low2 micro2 pico2 type2 t2))
+       (setq high (+ high high2)
+             low (+ low low2)
+             micro (+ micro micro2)
+             pico (+ pico pico2)
+             type (max type type2))
+       (when (>= pico 1000000)
+         (setq micro (1+ micro)
+               pico (- pico 1000000)))
+       (when (>= micro 1000000)
+         (setq low (1+ low)
+               micro (- micro 1000000)))
+       (when (>= low 65536)
+         (setq high (1+ high)
+               low (- low 65536)))
+       (encode-time-value high low micro pico type)))
+
+    (defun time-subtract (t1 t2)
+      "Subtract two time values, T1 minus T2.
 Return the difference in the format of a time value."
-  (with-decoded-time-value ((high low micro pico type t1)
-                           (high2 low2 micro2 pico2 type2 t2))
-    (setq high (- high high2)
-         low (- low low2)
-         micro (- micro micro2)
-         pico (- pico pico2)
-         type (max type type2))
-    (when (< pico 0)
-      (setq micro (1- micro)
-           pico (+ pico 1000000)))
-    (when (< micro 0)
-      (setq low (1- low)
-           micro (+ micro 1000000)))
-    (when (< low 0)
-      (setq high (1- high)
-           low (+ low 65536)))
-    (encode-time-value high low micro pico type)))
-
-;;;###autoload
-(defun time-add (t1 t2)
-  "Add two time values T1 and T2.  One should represent a time difference."
-  (with-decoded-time-value ((high low micro pico type t1)
-                           (high2 low2 micro2 pico2 type2 t2))
-    (setq high (+ high high2)
-         low (+ low low2)
-         micro (+ micro micro2)
-         pico (+ pico pico2)
-         type (max type type2))
-    (when (>= pico 1000000)
-      (setq micro (1+ micro)
-           pico (- pico 1000000)))
-    (when (>= micro 1000000)
-      (setq low (1+ low)
-           micro (- micro 1000000)))
-    (when (>= low 65536)
-      (setq high (1+ high)
-           low (- low 65536)))
-    (encode-time-value high low micro pico type)))
+      (with-decoded-time-value ((high low micro pico type t1)
+                               (high2 low2 micro2 pico2 type2 t2))
+       (setq high (- high high2)
+             low (- low low2)
+             micro (- micro micro2)
+             pico (- pico pico2)
+             type (max type type2))
+       (when (< pico 0)
+         (setq micro (1- micro)
+               pico (+ pico 1000000)))
+       (when (< micro 0)
+         (setq low (1- low)
+               micro (+ micro 1000000)))
+       (when (< low 0)
+         (setq high (1- high)
+               low (+ low 65536)))
+       (encode-time-value high low micro pico type)))
+
+    (defun time-less-p (t1 t2)
+      "Return non-nil if time value T1 is earlier than time value T2."
+      (with-decoded-time-value ((high1 low1 micro1 pico1 type1 t1)
+                               (high2 low2 micro2 pico2 type2 t2))
+       (or (< high1 high2)
+           (and (= high1 high2)
+                (or (< low1 low2)
+                    (and (= low1 low2)
+                         (or (< micro1 micro2)
+                             (and (= micro1 micro2)
+                                  (< pico1 pico2)))))))))))
 
 ;;;###autoload
 (defun date-to-day (date)
@@ -272,11 +290,9 @@ DATE1 and DATE2 should be date-time strings."
           (not (zerop (% year 100))))
       (zerop (% year 400))))
 
-;;;###autoload
-(defun time-to-day-in-year (time)
-  "Return the day number within the year corresponding to TIME."
-  (let* ((tim (decode-time time))
-        (month (nth 4 tim))
+(defun time-date--day-in-year (tim)
+  "Return the day number within the year corresponding to the decoded time TIM."
+  (let* ((month (nth 4 tim))
         (day (nth 3 tim))
         (year (nth 5 tim))
         (day-of-year (+ day (* 31 (1- month)))))
@@ -286,6 +302,11 @@ DATE1 and DATE2 should be date-time strings."
        (setq day-of-year (1+ day-of-year))))
     day-of-year))
 
+;;;###autoload
+(defun time-to-day-in-year (time)
+  "Return the day number within the year corresponding to TIME."
+  (time-date--day-in-year (decode-time time)))
+
 ;;;###autoload
 (defun time-to-days (time)
   "The number of days between the Gregorian date 0001-12-31bce and TIME.
@@ -293,7 +314,7 @@ TIME should be a time value.
 The Gregorian date Sunday, December 31, 1bce is imaginary."
   (let* ((tim (decode-time time))
         (year (nth 5 tim)))
-    (+ (time-to-day-in-year time)      ;       Days this year
+    (+ (time-date--day-in-year tim)    ;       Days this year
        (* 365 (1- year))               ;       + Days in prior years
        (/ (1- year) 4)                 ;       + Julian leap years
        (- (/ (1- year) 100))           ;       - century years
index 168637a..cef8609 100644 (file)
@@ -1,3 +1,30 @@
+2014-12-18  Eric Abrahamsen <eric@ericabrahamsen.net>
+
+       * gnus.texi (Gnus Registry Setup): Explain pruning changes. Mention
+       gnus-registry-prune-factor. Explain sorting changes and
+       gnus-registry-default-sort-function. Correct file extension.
+
+2014-11-10  Katsumi Yamaoka  <yamaoka@jpl.org>
+
+       * gnus.texi (Top): Add missing `HTML' menu.
+       (HTML): Fix xref to FAQ 4-16.
+
+2014-11-07  Tassilo Horn  <tsdh@gnu.org>
+
+       * gnus.texi (HTML): Update section so that it mentions shr and w3m.
+       Also link the full EWW manual that explains more on shr, too.
+
+       * gnus-faq.texi (FAQ 4 - Reading messages, FAQ 4-16): Add Q&A on how to
+       increase contrast when displaying HTML mail with shr.
+
+2014-11-02  Teodor Zlatanov  <tzz@lifelogs.com>
+
+       * auth.texi (Help for users): Explain quoting rules better.
+
+2014-10-25  Eric S. Raymond  <esr@thyrsus.com>
+
+       * gnus-coding.texi: Neutralized language specific to a repository type.
+
 2014-07-31  Tassilo Horn  <tsdh@gnu.org>
 
        * gnus.texi (Group Parameters): Document that `gcc-self' may also be a
index 521358a..94e0871 100644 (file)
@@ -106,12 +106,17 @@ The @code{user} is the user name.  It's known as @var{:user} in
 @code{auth-source-search} queries.  You can also use @code{login} and
 @code{account}.
 
-Spaces are always OK as far as auth-source is concerned (but other
-programs may not like them).  Just put the data in quotes, escaping
-quotes as you'd expect with @samp{\}.
+You can use spaces inside a password or other token by surrounding the
+token with either single or double quotes.
 
-All these are optional.  You could just say (but we don't recommend
-it, we're just showing that it's possible)
+You can use single quotes inside a password or other token by
+surrounding it with double quotes, e.g. @code{"he'llo"}. Similarly you
+can use double quotes inside a password or other token by surrounding
+it with single quotes, e.g. @code{'he"llo'}. You can't mix both (so a
+password or other token can't have both single and double quotes).
+
+All this is optional. You could just say (but we don't recommend it,
+we're just showing that it's possible)
 
 @example
 password @var{mypassword}
index 0b2b063..adbdd68 100644 (file)
@@ -313,17 +313,17 @@ If it's a file which is thought of as being outside of Gnus (e.g., the
 new @file{encrypt.el}), you should probably make the change in the Emacs
 tree, and it will show up in the Gnus tree a few days later.
 
-If you don't have Emacs bzr access (or it's inconvenient), you can
-change such a file in the v5-10 branch, and it should propagate to Emacs
-bzr---however, it will get some extra scrutiny (by Miles) to see if the
-changes are possibly controversial and need discussion on the mailing
-list.  Many changes are obvious bug-fixes however, so often there won't
-be any problem.
+If you don't have Emacs repository access (or it's inconvenient), you
+can change such a file in the v5-10 branch, and it should propagate to
+the Emacs repository---however, it will get some extra scrutiny (by
+Miles) to see if the changes are possibly controversial and need
+discussion on the mailing list.  Many changes are obvious bug-fixes
+however, so often there won't be any problem.
 
 @item
 If it's to a Gnus file, and it's important enough that it should be part
 of Emacs and the v5-10 branch, then you can make the change on the v5-10
-branch, and it will go into Emacs bzr and the Gnus git trunk (a few days
+branch, and it will go into Emacs and the Gnus git trunk (a few days
 later).  The most prominent examples for such changes are bug-fixed
 including improvements on the documentation.
 
index fd4f427..3e01fab 100644 (file)
@@ -742,6 +742,7 @@ POP3 mail source.  See @pxref{Mail Source Specifiers} for VALUE.
 * FAQ 4-14::    I don't like the way the Summary buffer looks, how to
                 tweak it?
 * FAQ 4-15::    How to split incoming mails in several groups?
+* FAQ 4-16::    How can I ensure more contrast when viewing HTML mail?
 @end menu
 
 @node FAQ 4-1
@@ -1185,6 +1186,21 @@ from using them):
 @end example
 @noindent
 
+@node FAQ 4-16
+@subsubheading Question 4.16
+
+How can I ensure more contrast when viewing HTML mail?
+
+@subsubheading Answer
+
+Gnus' built-in simple HTML renderer (you use it if the value of
+@code{mm-text-html-renderer} is @code{shr}) uses the colors which are
+declared in the HTML mail.  However, it adjusts them in order to
+prevent situations like dark gray text on black background.  In case
+the results still have a too low contrast for you, increase the values
+of the variables @code{shr-color-visible-distance-min} and
+@code{shr-color-visible-luminance-min}.
+
 @node FAQ 5 - Composing messages
 @subsection Composing messages
 
@@ -1633,7 +1649,7 @@ aren't they and how to fix it?
 
 @subsubheading Answer
 
-The message-ID is an unique identifier for messages you
+The message-ID is a unique identifier for messages you
 send. To make it unique, Gnus need to know which machine
 name to put after the "@@". If the name of the machine
 where Gnus is running isn't suitable (it probably isn't
index 6f47786..43dadfc 100644 (file)
@@ -618,6 +618,7 @@ Article Buffer
 
 * Hiding Headers::              Deciding what headers should be displayed.
 * Using MIME::                  Pushing articles through @acronym{MIME} before reading them.
+* HTML::                        Reading @acronym{HTML} messages.
 * Customizing Articles::        Tailoring the look of the articles.
 * Article Keymap::              Keystrokes available in the article buffer.
 * Misc Article::                Other stuff.
@@ -11761,20 +11762,30 @@ Also @pxref{MIME Commands}.
 @section @acronym{HTML}
 @cindex @acronym{HTML}
 
-If you have @code{w3m} installed on your system, Gnus can display
-@acronym{HTML} articles in the article buffer.  There are many Gnus
-add-ons for doing this, using various approaches, but there's one
-(sort of) built-in method that's used by default.
+Gnus can display @acronym{HTML} articles nicely formatted in the
+article buffer.  There are many methods for doing that, but two of
+them are kind of default methods.
+
+If your Emacs copy has been built with libxml2 support, then Gnus uses
+Emacs' built-in, plain elisp Simple HTML Renderer @code{shr}
+@footnote{@code{shr} displays colors as declared in the @acronym{HTML}
+article but tries to adjust them in order to be readable.  If you
+prefer more contrast, @xref{FAQ 4-16}.} which is also used by Emacs'
+browser EWW (@pxref{EWW, ,EWW, emacs, The Emacs Manual}).
+
+If your Emacs copy lacks libxml2 support but you have @code{w3m}
+installed on your system, Gnus uses that to render @acronym{HTML} mail
+and display the results in the article buffer (@code{gnus-w3m}).
 
-For a complete overview, consult @xref{Display Customization,
-,Display Customization, emacs-mime, The Emacs MIME Manual}.  This
-section only describes the default method.
+For a complete overview, consult @xref{Display Customization, ,Display
+Customization, emacs-mime, The Emacs MIME Manual}.  This section only
+describes the default method.
 
 @table @code
 @item mm-text-html-renderer
 @vindex mm-text-html-renderer
-If set to @code{gnus-article-html}, Gnus will use the built-in method,
-that's based on @code{w3m}.
+If set to @code{shr}, Gnus uses its own simple @acronym{HTML}
+renderer.  If set to @code{gnus-w3m}, it uses @code{w3m}.
 
 @item gnus-blocked-images
 @vindex gnus-blocked-images
@@ -25942,17 +25953,34 @@ the word ``archive'' is not followed.
 
 @defvar gnus-registry-max-entries
 The number (an integer or @code{nil} for unlimited) of entries the
-registry will keep.
+registry will keep.  If the registry has reached or exceeded this
+size, it will reject insertion of new entries.
+@end defvar
+
+@defvar gnus-registry-prune-factor
+This option (a float between 0 and 1) controls how much the registry
+is cut back during pruning.  In order to prevent constant pruning, the
+registry will be pruned back to less than
+@code{gnus-registry-max-entries}.  This option controls exactly how
+much less: the target is calculated as the maximum number of entries
+minus the maximum number times this factor.  The default is 0.1:
+i.e. if your registry is limited to 50000 entries, pruning will try to
+cut back to 45000 entries.  Entries with keys marked as precious will
+not be pruned.
 @end defvar
 
-@defvar gnus-registry-max-pruned-entries
-The maximum number (an integer or @code{nil} for unlimited) of entries
-the registry will keep after pruning.
+@defvar gnus-registry-default-sort-function
+This option specifies how registry entries are sorted during pruning.
+If a function is given, it should sort least valuable entries first,
+as pruning starts from the beginning of the list.  The default value
+is @code{gnus-registry-sort-by-creation-time}, which proposes the
+oldest entries for pruning.  Set to nil to perform no sorting, which
+will speed up the pruning process.
 @end defvar
 
 @defvar gnus-registry-cache-file
 The file where the registry will be stored between Gnus sessions.  By
-default the file name is @code{.gnus.registry.eioio} in the same
+default the file name is @code{.gnus.registry.eieio} in the same
 directory as your @code{.newsrc.eld}.
 @end defvar