summaryrefslogtreecommitdiff
path: root/lisp/gnus
diff options
context:
space:
mode:
authorGnus developers <ding@gnus.org>2010-09-26 04:03:19 +0000
committerKatsumi Yamaoka <yamaoka@jpl.org>2010-09-26 04:03:19 +0000
commit8ccbef23ea624d892bada3c66ef2339ada342997 (patch)
treeb8baaa6929a0742ffd301529bcc27001dd08e031 /lisp/gnus
parent83e245c4906513429cb56629485deb5f04a240a3 (diff)
downloademacs-8ccbef23ea624d892bada3c66ef2339ada342997.tar.gz
Merge changes made in Gnus trunk.
nnimap.el: Implement partial IMAP article fetch. nnimap.el: Have nnimap not update the infos if it can't get info from the server. Implement functions for showing the complete articles. gnus-int.el (gnus-open-server): Don't query whether to go offline -- just do it. gnus-art.el (gnus-mime-delete-part): Fix plural for "byte" when there isn't a single byte. nndoc.el (nndoc-type-alist): Move mime-parts after mbox. Suggested by Jay Berkenbilt. mm-decode.el (mm-save-part): Allow saving to other directories the normal Emacs way. gnus-html.el (gnus-html-rescale-image): Use our defalias gnus-window-inside-pixel-edges. gnus-srvr.el (gnus-server-copy-server): Add documentation. gnus.texi (Using IMAP): Document the new nnimap. nnimap.el (nnimap-wait-for-response): Search further when we're not using streaming. gnus-int.el (gnus-check-server): Say what the error was when opening failed. nnheader.el (nnheader-get-report-string): New function. gnus-int.el (gnus-check-server): Use report-string. nnimap.el (nnimap-open-connection): Add more error reporting when nnimap fails early. gnus-start.el (gnus-get-unread-articles): Don't try to open failed servers twice. nnimap.el (nnimap-wait-for-response): Reversed logic in the nnimap-streaming test. gnus-art.el: Removed CTAN button stuff, which I don't think is very relevant any more. Remove NoCeM support, since nobody seems to use it any more. Remove earcon and gnus-audio. gnus.el (gnus): Silence gnus-load message. gnus-group.el (gnus-read-ephemeral-bug-group): Add the bug email address to the To list for easier response. gnus.texi (Connecting to an IMAP Server): Show how to use as primary method instead of secondary.
Diffstat (limited to 'lisp/gnus')
-rw-r--r--lisp/gnus/earcon.el230
-rw-r--r--lisp/gnus/gnus-art.el120
-rw-r--r--lisp/gnus/gnus-audio.el149
-rw-r--r--lisp/gnus/gnus-cus.el5
-rw-r--r--lisp/gnus/gnus-demon.el9
-rw-r--r--lisp/gnus/gnus-group.el16
-rw-r--r--lisp/gnus/gnus-html.el9
-rw-r--r--lisp/gnus/gnus-int.el68
-rw-r--r--lisp/gnus/gnus-nocem.el452
-rw-r--r--lisp/gnus/gnus-srvr.el62
-rw-r--r--lisp/gnus/gnus-start.el15
-rw-r--r--lisp/gnus/gnus-sum.el25
-rw-r--r--lisp/gnus/gnus.el37
-rw-r--r--lisp/gnus/mm-decode.el24
-rw-r--r--lisp/gnus/mml1991.el95
-rw-r--r--lisp/gnus/mml2015.el365
-rw-r--r--lisp/gnus/nndoc.el6
-rw-r--r--lisp/gnus/nnheader.el12
-rw-r--r--lisp/gnus/nnimap.el269
19 files changed, 418 insertions, 1550 deletions
diff --git a/lisp/gnus/earcon.el b/lisp/gnus/earcon.el
deleted file mode 100644
index 2086f86c417..00000000000
--- a/lisp/gnus/earcon.el
+++ /dev/null
@@ -1,230 +0,0 @@
-;;; earcon.el --- Sound effects for messages
-
-;; Copyright (C) 1996, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
-
-;; Author: Steven L. Baur <steve@miranova.com>
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-;; This file provides access to sound effects in Gnus.
-
-;;; Code:
-
-(eval-when-compile (require 'cl))
-(require 'gnus)
-(require 'gnus-audio)
-(require 'gnus-art)
-
-(defgroup earcon nil
- "Turn ** sounds ** into noise."
- :group 'gnus-visual)
-
-(defcustom earcon-prefix "**"
- "*String denoting the start of an earcon."
- :type 'string
- :group 'earcon)
-
-(defcustom earcon-suffix "**"
- "String denoting the end of an earcon."
- :type 'string
- :group 'earcon)
-
-(defcustom earcon-regexp-alist
- '(("boring" 1 "Boring.au")
- ("evil[ \t]+laugh" 1 "Evil_Laugh.au")
- ("gag\\|puke" 1 "Puke.au")
- ("snicker" 1 "Snicker.au")
- ("meow" 1 "catmeow.wav")
- ("sob\\|boohoo" 1 "cry.wav")
- ("drum[ \t]*roll" 1 "drumroll.au")
- ("blast" 1 "explosion.au")
- ("flush\\|plonk!*" 1 "flush.au")
- ("kiss" 1 "kiss.wav")
- ("tee[ \t]*hee" 1 "laugh.au")
- ("shoot" 1 "shotgun.wav")
- ("yawn" 1 "snore.wav")
- ("cackle" 1 "witch.au")
- ("yell\\|roar" 1 "yell2.au")
- ("whoop-de-doo" 1 "whistle.au"))
- "*A list of regexps to map earcons to real sounds."
- :type '(repeat (list regexp
- (integer :tag "Match")
- (string :tag "Sound")))
- :group 'earcon)
-(defvar earcon-button-marker-list nil)
-(make-variable-buffer-local 'earcon-button-marker-list)
-
-;;; FIXME!! clone of code from gnus-vis.el FIXME!!
-(defun earcon-article-push-button (event)
- "Check text under the mouse pointer for a callback function.
-If the text under the mouse pointer has a `earcon-callback' property,
-call it with the value of the `earcon-data' text property."
- (interactive "e")
- (set-buffer (window-buffer (posn-window (event-start event))))
- (let* ((pos (posn-point (event-start event)))
- (data (get-text-property pos 'earcon-data))
- (fun (get-text-property pos 'earcon-callback)))
- (if fun (funcall fun data))))
-
-(defun earcon-article-press-button ()
- "Check text at point for a callback function.
-If the text at point has a `earcon-callback' property,
-call it with the value of the `earcon-data' text property."
- (interactive)
- (let* ((data (get-text-property (point) 'earcon-data))
- (fun (get-text-property (point) 'earcon-callback)))
- (if fun (funcall fun data))))
-
-(defun earcon-article-prev-button (n)
- "Move point to N buttons backward.
-If N is negative, move forward instead."
- (interactive "p")
- (earcon-article-next-button (- n)))
-
-(defun earcon-article-next-button (n)
- "Move point to N buttons forward.
-If N is negative, move backward instead."
- (interactive "p")
- (let ((function (if (< n 0) 'previous-single-property-change
- 'next-single-property-change))
- (inhibit-point-motion-hooks t)
- (backward (< n 0))
- (limit (if (< n 0) (point-min) (point-max))))
- (setq n (abs n))
- (while (and (not (= limit (point)))
- (> n 0))
- ;; Skip past the current button.
- (when (get-text-property (point) 'earcon-callback)
- (goto-char (funcall function (point) 'earcon-callback nil limit)))
- ;; Go to the next (or previous) button.
- (gnus-goto-char (funcall function (point) 'earcon-callback nil limit))
- ;; Put point at the start of the button.
- (when (and backward (not (get-text-property (point) 'earcon-callback)))
- (goto-char (funcall function (point) 'earcon-callback nil limit)))
- ;; Skip past intangible buttons.
- (when (get-text-property (point) 'intangible)
- (incf n))
- (decf n))
- (unless (zerop n)
- (gnus-message 5 "No more buttons"))
- n))
-
-(defun earcon-article-add-button (from to fun &optional data)
- "Create a button between FROM and TO with callback FUN and data DATA."
- (and (boundp gnus-article-button-face)
- gnus-article-button-face
- (gnus-overlay-put (gnus-make-overlay from to)
- 'face gnus-article-button-face))
- (gnus-add-text-properties
- from to
- (nconc (and gnus-article-mouse-face
- (list gnus-mouse-face-prop gnus-article-mouse-face))
- (list 'gnus-callback fun)
- (and data (list 'gnus-data data)))))
-
-(defun earcon-button-entry ()
- ;; Return the first entry in `gnus-button-alist' matching this place.
- (let ((alist earcon-regexp-alist)
- (case-fold-search t)
- (entry nil))
- (while alist
- (setq entry (pop alist))
- (if (looking-at (car entry))
- (setq alist nil)
- (setq entry nil)))
- entry))
-
-(defun earcon-button-push (marker)
- ;; Push button starting at MARKER.
- (with-current-buffer gnus-article-buffer
- (goto-char marker)
- (let* ((entry (earcon-button-entry))
- (inhibit-point-motion-hooks t)
- (fun 'gnus-audio-play)
- (args (list (nth 2 entry))))
- (cond
- ((fboundp fun)
- (apply fun args))
- ((and (boundp fun)
- (fboundp (symbol-value fun)))
- (apply (symbol-value fun) args))
- (t
- (gnus-message 1 "You must define `%S' to use this button"
- (cons fun args)))))))
-
-;;; FIXME!! clone of code from gnus-vis.el FIXME!!
-
-;;;###interactive
-(defun earcon-region (beg end)
- "Play Sounds in the region between point and mark."
- (interactive "r")
- (earcon-buffer (current-buffer) beg end))
-
-;;;###interactive
-(defun earcon-buffer (&optional buffer st nd)
- (interactive)
- (save-excursion
- ;; clear old markers.
- (if (boundp 'earcon-button-marker-list)
- (while earcon-button-marker-list
- (set-marker (pop earcon-button-marker-list) nil))
- (setq earcon-button-marker-list nil))
- (and buffer (set-buffer buffer))
- (let ((buffer-read-only nil)
- (inhibit-point-motion-hooks t)
- (case-fold-search t)
- (alist earcon-regexp-alist)
- beg entry regexp)
- (goto-char (point-min))
- (setq beg (point))
- (while (setq entry (pop alist))
- (setq regexp (concat (regexp-quote earcon-prefix)
- ".*\\("
- (car entry)
- "\\).*"
- (regexp-quote earcon-suffix)))
- (goto-char beg)
- (while (re-search-forward regexp nil t)
- (let* ((start (and entry (match-beginning 1)))
- (end (and entry (match-end 1)))
- (from (match-beginning 1)))
- (earcon-article-add-button
- start end 'earcon-button-push
- (car (push (set-marker (make-marker) from)
- earcon-button-marker-list)))
- (gnus-audio-play (caddr entry))))))))
-
-;;;###autoload
-(defun gnus-earcon-display ()
- "Play sounds in message buffers."
- (interactive)
- (with-current-buffer gnus-article-buffer
- (goto-char (point-min))
- ;; Skip headers
- (unless (search-forward "\n\n" nil t)
- (goto-char (point-max)))
- (sit-for 0)
- (earcon-buffer (current-buffer) (point))))
-
-;;;***
-
-(provide 'earcon)
-
-(run-hooks 'earcon-load-hook)
-
-;;; earcon.el ends here
diff --git a/lisp/gnus/gnus-art.el b/lisp/gnus/gnus-art.el
index fd6957d9aac..8a0f0a3c388 100644
--- a/lisp/gnus/gnus-art.el
+++ b/lisp/gnus/gnus-art.el
@@ -257,6 +257,22 @@ This can also be a list of the above values."
(regexp :value ".*"))
:group 'gnus-article-signature)
+(defcustom gnus-fetch-partial-articles nil
+ "If non-nil, Gnus will fetch partial articles.
+If t, nnimap will fetch only the first part. If a string, it
+will fetch all parts that have types that match that string. A
+likely value would be \"text/\" to automatically fetch all
+textual parts.
+
+Currently only the nnimap backend actually supports partial
+article fetching. If the backend doesn't support it, it has no
+effect."
+ :version "24.1"
+ :type '(choice (const nil)
+ (const t)
+ (regexp))
+ :group 'gnus-article)
+
(defcustom gnus-hidden-properties '(invisible t intangible t)
"Property list to use for hiding text."
:type 'sexp
@@ -1598,15 +1614,6 @@ predicate. See Info node `(gnus)Customizing Articles'."
:link '(custom-manual "(gnus)Customizing Articles")
:type gnus-article-treat-custom)
-(defcustom gnus-treat-play-sounds nil
- "Play sounds.
-Valid values are nil, t, `head', `first', `last', an integer or a
-predicate. See Info node `(gnus)Customizing Articles'."
- :version "21.1"
- :group 'gnus-article-treat
- :link '(custom-manual "(gnus)Customizing Articles")
- :type gnus-article-treat-custom)
-
(defcustom gnus-treat-x-pgp-sig nil
"Verify X-PGP-Sig.
To automatically treat X-PGP-Sig, set it to head.
@@ -1711,8 +1718,7 @@ This requires GNU Libidn, and by default only enabled if it is found."
(gnus-treat-hide-citation gnus-article-hide-citation)
(gnus-treat-hide-citation-maybe gnus-article-hide-citation-maybe)
(gnus-treat-highlight-citation gnus-article-highlight-citation)
- (gnus-treat-body-boundary gnus-article-treat-body-boundary)
- (gnus-treat-play-sounds gnus-earcon-display)))
+ (gnus-treat-body-boundary gnus-article-treat-body-boundary)))
(defvar gnus-article-mime-handle-alist nil)
(defvar article-lapsed-timer nil)
@@ -5075,7 +5081,10 @@ Deleting parts may malfunction or destroy the article; continue? "))
"|\n"
"| Type: " type "\n"
"| Filename: " filename "\n"
- "| Size (encoded): " bsize " Byte\n"
+ "| Size (encoded): " bsize (format " byte%s\n"
+ (if (= bsize 1)
+ ""
+ "s"))
(when description
(concat "| Description: " description "\n"))
"`----\n"))
@@ -7030,9 +7039,7 @@ groups."
(gnus-backlog-remove-article
(car gnus-article-current) (cdr gnus-article-current)))
;; Flush original article as well.
- (when (get-buffer gnus-original-article-buffer)
- (with-current-buffer gnus-original-article-buffer
- (setq gnus-original-article nil)))
+ (gnus-flush-original-article-buffer)
(when gnus-use-cache
(gnus-cache-update-article
(car gnus-article-current) (cdr gnus-article-current)))
@@ -7046,6 +7053,11 @@ groups."
(set-window-point (get-buffer-window buf) (point)))
(gnus-summary-show-article))
+(defun gnus-flush-original-article-buffer ()
+ (when (get-buffer gnus-original-article-buffer)
+ (with-current-buffer gnus-original-article-buffer
+ (setq gnus-original-article nil))))
+
(defun gnus-article-edit-exit ()
"Exit the article editing without updating."
(interactive)
@@ -7134,46 +7146,6 @@ man page."
(function :tag "Other"))
:group 'gnus-article-buttons)
-(defcustom gnus-ctan-url "http://tug.ctan.org/tex-archive/"
- "Top directory of a CTAN \(Comprehensive TeX Archive Network\) archive.
-If the default site is too slow, try to find a CTAN mirror, see
-<URL:http://tug.ctan.org/tex-archive/CTAN.sites?action=/index.html>. See also
-the variable `gnus-button-handle-ctan'."
- :version "22.1"
- :group 'gnus-article-buttons
- :link '(custom-manual "(gnus)Group Parameters")
- :type '(choice (const "http://www.tex.ac.uk/tex-archive/")
- (const "http://tug.ctan.org/tex-archive/")
- (const "http://www.dante.de/CTAN/")
- (string :tag "Other")))
-
-(defcustom gnus-button-ctan-handler 'browse-url
- "Function to use for displaying CTAN links.
-The function must take one argument, the string naming the URL."
- :version "22.1"
- :type '(choice (function-item :tag "Browse Url" browse-url)
- (function :tag "Other"))
- :group 'gnus-article-buttons)
-
-(defcustom gnus-button-handle-ctan-bogus-regexp "^/?tex-archive/\\|^/"
- "Bogus strings removed from CTAN URLs."
- :version "22.1"
- :group 'gnus-article-buttons
- :type '(choice (const "^/?tex-archive/\\|/")
- (regexp :tag "Other")))
-
-(defcustom gnus-button-ctan-directory-regexp
- (regexp-opt
- (list "archive-tools" "biblio" "bibliography" "digests" "documentation"
- "dviware" "fonts" "graphics" "help" "indexing" "info" "language"
- "languages" "macros" "nonfree" "obsolete" "support" "systems"
- "tds" "tools" "usergrps" "web") t)
- "Regular expression for ctan directories.
-It should match all directories in the top level of `gnus-ctan-url'."
- :version "22.1"
- :group 'gnus-article-buttons
- :type 'regexp)
-
(defcustom gnus-button-mid-or-mail-regexp
(concat "\\b\\(<?" gnus-button-valid-localpart-regexp "@"
gnus-button-valid-fqdn-regexp
@@ -7431,26 +7403,6 @@ Calls `describe-variable' or `describe-function'."
(gnus-message 1 "Cannot locale library `%s'." url)
(find-file-read-only file))))
-(defun gnus-button-handle-ctan (url)
- "Call `browse-url' when pushing a CTAN URL button."
- (funcall
- gnus-button-ctan-handler
- (concat
- gnus-ctan-url
- (gnus-replace-in-string url gnus-button-handle-ctan-bogus-regexp ""))))
-
-(defcustom gnus-button-tex-level 5
- "*Integer that says how many TeX-related buttons Gnus will show.
-The higher the number, the more buttons will appear and the more false
-positives are possible. Note that you can set this variable local to
-specific groups. Setting it higher in TeX groups is probably a good idea.
-See Info node `(gnus)Group Parameters' and the variable `gnus-parameters' on
-how to set variables in specific groups."
- :version "22.1"
- :group 'gnus-article-buttons
- :link '(custom-manual "(gnus)Group Parameters")
- :type 'integer)
-
(defcustom gnus-button-man-level 5
"*Integer that says how many man-related buttons Gnus will show.
The higher the number, the more buttons will appear and the more false
@@ -7517,20 +7469,6 @@ positives are possible."
0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
("\\bmailto:\\([^ \n\t]+\\)"
0 (>= gnus-button-message-level 0) gnus-url-mailto 1)
- ;; CTAN
- ((concat "\\bCTAN:[ \t\n]?[^>)!;:,'\n\t ]*\\("
- gnus-button-ctan-directory-regexp
- "[^][>)!;:,'\n\t ]+\\)")
- 0 (>= gnus-button-tex-level 1) gnus-button-handle-ctan 1)
- ((concat "\\btex-archive/\\("
- gnus-button-ctan-directory-regexp
- "/[-_.a-z0-9/]+[-_./a-z0-9]+[/a-z0-9]\\)")
- 1 (>= gnus-button-tex-level 6) gnus-button-handle-ctan 1)
- ((concat
- "\\b\\("
- gnus-button-ctan-directory-regexp
- "/[-_.a-z0-9]+/[-_./a-z0-9]+[/a-z0-9]\\)")
- 1 (>= gnus-button-tex-level 8) gnus-button-handle-ctan 1)
;; Info Konqueror style <info:/foo/bar baz>.
;; Must come before " Gnus home-grown style".
("\\binfo://?\\([^'\">\n\t]+\\)"
@@ -8512,9 +8450,7 @@ For example:
(when gnus-keep-backlog
(gnus-backlog-remove-article
(car gnus-article-current) (cdr gnus-article-current)))
- (when (get-buffer gnus-original-article-buffer)
- (with-current-buffer gnus-original-article-buffer
- (setq gnus-original-article nil)))
+ (gnus-flush-original-article-buffer)
(when gnus-use-cache
(gnus-cache-update-article
(car gnus-article-current) (cdr gnus-article-current))))))))
diff --git a/lisp/gnus/gnus-audio.el b/lisp/gnus/gnus-audio.el
deleted file mode 100644
index cc198176f10..00000000000
--- a/lisp/gnus/gnus-audio.el
+++ /dev/null
@@ -1,149 +0,0 @@
-;;; gnus-audio.el --- Sound effects for Gnus
-
-;; Copyright (C) 1996, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
-
-;; Author: Steven L. Baur <steve@miranova.com>
-;; Keywords: news, mail, multimedia
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;; This file provides access to sound effects in Gnus.
-;; This file is partially stripped to support earcons.el.
-
-;;; Code:
-
-(require 'nnheader)
-
-(defgroup gnus-audio nil
- "Playing sound in Gnus."
- :version "21.1"
- :group 'gnus-visual
- :group 'multimedia)
-
-(defvar gnus-audio-inline-sound
- (or (if (fboundp 'device-sound-enabled-p)
- (device-sound-enabled-p)) ; XEmacs
- (fboundp 'play-sound)) ; Emacs
- "Non-nil means try to play sounds without using an external program.")
-
-(defcustom gnus-audio-directory (nnheader-find-etc-directory "sounds")
- "The directory containing the Sound Files."
- :type '(choice directory (const nil))
- :group 'gnus-audio)
-
-(defcustom gnus-audio-au-player (executable-find "play")
- "Executable program for playing sun AU format sound files."
- :group 'gnus-audio
- :type '(choice file (const nil)))
-
-(defcustom gnus-audio-wav-player (executable-find "play")
- "Executable program for playing WAV files."
- :group 'gnus-audio
- :type '(choice file (const nil)))
-
-;;; The following isn't implemented yet. Wait for Millennium Gnus.
-;;(defvar gnus-audio-effects-enabled t
-;; "When t, Gnus will use sound effects.")
-;;(defvar gnus-audio-enable-hooks nil
-;; "Functions run when enabling sound effects.")
-;;(defvar gnus-audio-disable-hooks nil
-;; "Functions run when disabling sound effects.")
-;;(defvar gnus-audio-theme-song nil
-;; "Theme song for Gnus.")
-;;(defvar gnus-audio-enter-group nil
-;; "Sound effect played when selecting a group.")
-;;(defvar gnus-audio-exit-group nil
-;; "Sound effect played when exiting a group.")
-;;(defvar gnus-audio-score-group nil
-;; "Sound effect played when scoring a group.")
-;;(defvar gnus-audio-busy-sound nil
-;; "Sound effect played when going into a ... sequence.")
-
-
-;;;###autoload
-;;(defun gnus-audio-enable-sound ()
-;; "Enable Sound Effects for Gnus."
-;; (interactive)
-;; (setq gnus-audio-effects-enabled t)
-;; (gnus-run-hooks gnus-audio-enable-hooks))
-
-;;;###autoload
- ;(defun gnus-audio-disable-sound ()
-;; "Disable Sound Effects for Gnus."
-;; (interactive)
-;; (setq gnus-audio-effects-enabled nil)
-;; (gnus-run-hooks gnus-audio-disable-hooks))
-
-;;;###autoload
-(defun gnus-audio-play (file)
- "Play a sound FILE through the speaker."
- (interactive "fSound file name: ")
- (let ((sound-file (if (file-exists-p file)
- file
- (expand-file-name file gnus-audio-directory))))
- (when (file-exists-p sound-file)
- (cond ((and gnus-audio-inline-sound
- (condition-case nil
- ;; Even if we have audio, we may fail with the
- ;; wrong sort of sound file.
- (progn (play-sound-file sound-file)
- t)
- (error nil))))
- ;; If we don't have built-in sound, or playing it failed,
- ;; try with external program.
- ((equal "wav" (file-name-extension sound-file))
- (call-process gnus-audio-wav-player
- sound-file
- 0
- nil
- sound-file))
- ((equal "au" (file-name-extension sound-file))
- (call-process gnus-audio-au-player
- sound-file
- 0
- nil
- sound-file))))))
-
-
-;;; The following isn't implemented yet, wait for Red Gnus
-;;(defun gnus-audio-startrek-sounds ()
-;; "Enable sounds from Star Trek the original series."
-;; (interactive)
-;; (setq gnus-audio-busy-sound "working.au")
-;; (setq gnus-audio-enter-group "bulkhead_door.au")
-;; (setq gnus-audio-exit-group "bulkhead_door.au")
-;; (setq gnus-audio-score-group "ST_laser.au")
-;; (setq gnus-audio-theme-song "startrek.au")
-;; (add-hook 'gnus-select-group-hook 'gnus-audio-startrek-select-group)
-;; (add-hook 'gnus-exit-group-hook 'gnus-audio-startrek-exit-group))
-;;;***
-
-(defvar gnus-startup-jingle "Tuxedomoon.Jingle4.au"
- "Name of the Gnus startup jingle file.")
-
-(defun gnus-play-jingle ()
- "Play the Gnus startup jingle, unless that's inhibited."
- (interactive)
- (gnus-audio-play gnus-startup-jingle))
-
-(provide 'gnus-audio)
-
-(run-hooks 'gnus-audio-load-hook)
-
-;;; gnus-audio.el ends here
diff --git a/lisp/gnus/gnus-cus.el b/lisp/gnus/gnus-cus.el
index 838150d1146..6da91bdc266 100644
--- a/lisp/gnus/gnus-cus.el
+++ b/lisp/gnus/gnus-cus.el
@@ -865,11 +865,6 @@ This can be changed using the `\\[gnus-score-change-score-file]' command."
Check the [ ] for the entries you want to apply to this score file, then
edit the value to suit your taste. Don't forget to mark the checkbox,
if you do all your changes will be lost. ")
- (widget-create 'push-button
- :action (lambda (&rest ignore)
- (require 'gnus-audio)
- (gnus-audio-play "Evil_Laugh.au"))
- "Bhahahah!")
(widget-insert "\n\n")
(make-local-variable 'gnus-custom-scores)
(setq gnus-custom-scores
diff --git a/lisp/gnus/gnus-demon.el b/lisp/gnus/gnus-demon.el
index 67c1c8ba3bc..c4e439c3bf4 100644
--- a/lisp/gnus/gnus-demon.el
+++ b/lisp/gnus/gnus-demon.el
@@ -240,15 +240,6 @@ time Emacs has been idle for IDLE `gnus-demon-timestep's."
;; this idle-cycle.
(push (car handler) gnus-demon-idle-has-been-called)))))))))
-(defun gnus-demon-add-nocem ()
- "Add daemonic NoCeM handling to Gnus."
- (gnus-demon-add-handler 'gnus-demon-scan-nocem 60 30))
-
-(defun gnus-demon-scan-nocem ()
- "Scan NoCeM groups for NoCeM messages."
- (save-window-excursion
- (gnus-nocem-scan-groups)))
-
(defun gnus-demon-add-disconnection ()
"Add daemonic server disconnection to Gnus."
(gnus-demon-add-handler 'gnus-demon-close-connections nil 30))
diff --git a/lisp/gnus/gnus-group.el b/lisp/gnus/gnus-group.el
index 5a25d513a57..7dddb9b6f70 100644
--- a/lisp/gnus/gnus-group.el
+++ b/lisp/gnus/gnus-group.el
@@ -2418,6 +2418,14 @@ the bug number, and browsing the URL must return mbox output."
(let ((tmpfile (mm-make-temp-file "gnus-temp-group-")))
(with-temp-file tmpfile
(url-insert-file-contents (format mbox-url number))
+ (goto-char (point-min))
+ ;; Add the debbugs address so that we can respond to reports easily.
+ (while (re-search-forward "^To: " nil t)
+ (end-of-line)
+ (insert (format ", %s@%s" number
+ (replace-regexp-in-string
+ "/.*$" ""
+ (replace-regexp-in-string "^http://" "" mbox-url)))))
(write-region (point-min) (point-max) tmpfile)
(gnus-group-read-ephemeral-group
"gnus-read-ephemeral-bug"
@@ -3946,14 +3954,6 @@ re-scanning. If ARG is non-nil and not a number, this will force
(unless gnus-slave
(gnus-master-read-slave-newsrc))
- ;; We might read in new NoCeM messages here.
- (when (and gnus-use-nocem
- (or (and (numberp gnus-use-nocem)
- (numberp arg)
- (>= arg gnus-use-nocem))
- (not arg)))
- (gnus-nocem-scan-groups))
-
(gnus-get-unread-articles arg)
;; If the user wants it, we scan for new groups.
diff --git a/lisp/gnus/gnus-html.el b/lisp/gnus/gnus-html.el
index 5199f7dfd5f..cb5d3c6e30b 100644
--- a/lisp/gnus/gnus-html.el
+++ b/lisp/gnus/gnus-html.el
@@ -104,7 +104,12 @@ CHARS is a regexp-like character alternative (e.g., \"[)$]\")."
(match-string 0 encoded-text)))
t t encoded-text)
s (1+ s)))
- encoded-text)))))
+ encoded-text))))
+ ;; XEmacs does not have window-inside-pixel-edges
+ (defalias 'gnus-window-inside-pixel-edges
+ (if (fboundp 'window-inside-pixel-edges)
+ 'window-inside-pixel-edges
+ 'window-pixel-edges)))
(defun gnus-html-encode-url (url)
"Encode URL."
@@ -450,7 +455,7 @@ Return a string with image data."
image
(let* ((width (car size))
(height (cdr size))
- (edges (window-pixel-edges (get-buffer-window (current-buffer))))
+ (edges (gnus-window-inside-pixel-edges (get-buffer-window (current-buffer))))
(window-width (truncate (* gnus-max-image-proportion
(- (nth 2 edges) (nth 0 edges)))))
(window-height (truncate (* gnus-max-image-proportion
diff --git a/lisp/gnus/gnus-int.el b/lisp/gnus/gnus-int.el
index 395f47daf35..3245b16997b 100644
--- a/lisp/gnus/gnus-int.el
+++ b/lisp/gnus/gnus-int.el
@@ -181,10 +181,15 @@ If it is down, start it up (again)."
(prog1
(setq result (gnus-open-server method))
(unless silent
- (gnus-message 5 "Opening %s server%s...%s" (car method)
- (if (equal (nth 1 method) "") ""
- (format " on %s" (nth 1 method)))
- (if result "done" "failed")))))))
+ (gnus-message
+ (if result 5 3)
+ "Opening %s server%s...%s" (car method)
+ (if (equal (nth 1 method) "") ""
+ (format " on %s" (nth 1 method)))
+ (if result
+ "done"
+ (format "failed: %s"
+ (nnheader-get-report-string (car method))))))))))
(defun gnus-get-function (method function &optional noerror)
"Return a function symbol based on METHOD and FUNCTION."
@@ -265,36 +270,31 @@ If it is down, start it up (again)."
(setq elem (list gnus-command-method nil)
gnus-opened-servers (cons elem gnus-opened-servers)))
;; Set the status of this server.
- (setcar (cdr elem)
- (cond (result
- (if (eq open-server-function #'nnagent-open-server)
- ;; The agent's backend has a "special" status
- 'offline
- 'ok))
- ((and gnus-agent
- (gnus-agent-method-p gnus-command-method))
- (cond (gnus-server-unopen-status
- ;; Set the server's status to the unopen
- ;; status. If that status is offline,
- ;; recurse to open the agent's backend.
- (setq open-offline (eq gnus-server-unopen-status 'offline))
- gnus-server-unopen-status)
- ((and
- (not gnus-batch-mode)
- (gnus-y-or-n-p
- (format
- "Unable to open server %s (%s), go offline? "
- server
- (nnheader-get-report
- (car gnus-command-method)))))
- (setq open-offline t)
- 'offline)
- (t
- ;; This agentized server was still denied
- 'denied)))
- (t
- ;; This unagentized server must be denied
- 'denied)))
+ (setcar
+ (cdr elem)
+ (cond (result
+ (if (eq open-server-function #'nnagent-open-server)
+ ;; The agent's backend has a "special" status
+ 'offline
+ 'ok))
+ ((and gnus-agent
+ (gnus-agent-method-p gnus-command-method))
+ (cond
+ (gnus-server-unopen-status
+ ;; Set the server's status to the unopen
+ ;; status. If that status is offline,
+ ;; recurse to open the agent's backend.
+ (setq open-offline (eq gnus-server-unopen-status 'offline))
+ gnus-server-unopen-status)
+ ((not gnus-batch-mode)
+ (setq open-offline t)
+ 'offline)
+ (t
+ ;; This agentized server was still denied
+ 'denied)))
+ (t
+ ;; This unagentized server must be denied
+ 'denied)))
;; NOTE: I MUST set the server's status to offline before this
;; recursive call as this status will drive the
diff --git a/lisp/gnus/gnus-nocem.el b/lisp/gnus/gnus-nocem.el
deleted file mode 100644
index 0364c963a27..00000000000
--- a/lisp/gnus/gnus-nocem.el
+++ /dev/null
@@ -1,452 +0,0 @@
-;;; gnus-nocem.el --- NoCeM pseudo-cancellation treatment
-
-;; Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
-;; 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
-
-;; Author: Lars Magne Ingebrigtsen <larsi@gnus.org>
-;; Keywords: news
-
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software: you can redistribute it and/or modify
-;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation, either version 3 of the License, or
-;; (at your option) any later version.
-
-;; GNU Emacs is distributed in the hope that it will be useful,
-;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-;; GNU General Public License for more details.
-
-;; You should have received a copy of the GNU General Public License
-;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
-
-;;; Commentary:
-
-;;; Code:
-
-(eval-when-compile (require 'cl))
-
-(require 'gnus)
-(require 'nnmail)
-(require 'gnus-art)
-(require 'gnus-sum)
-(require 'gnus-range)
-
-(defgroup gnus-nocem nil
- "NoCeM pseudo-cancellation treatment."
- :group 'gnus-score)
-
-(defcustom gnus-nocem-groups
- '("news.lists.filters" "alt.nocem.misc")
- "*List of groups that will be searched for NoCeM messages."
- :group 'gnus-nocem
- :version "23.1"
- :type '(repeat (string :tag "Group")))
-
-(defcustom gnus-nocem-issuers
- '("Adri Verhoef"
- "alba-nocem@albasani.net"
- "bleachbot@httrack.com"
- "news@arcor-online.net"
- "news@uni-berlin.de"
- "nocem@arcor.de"
- "pgpmoose@killfile.org"
- "xjsppl@gmx.de")
- "*List of NoCeM issuers to pay attention to.
-
-This can also be a list of `(ISSUER CONDITION ...)' elements.
-
-See <URL:http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html> for an
-issuer registry."
- :group 'gnus-nocem
- :link '(url-link "http://www.xs4all.nl/~rosalind/nocemreg/nocemreg.html")
- :version "23.1"
- :type '(repeat (cons :format "%v" (string :tag "Issuer")
- (repeat :tag "Condition"
- (group (checklist :inline t (const not))
- (regexp :tag "Type" :value ".*")))))
- :get (lambda (symbol)
- (mapcar (lambda (elem)
- (if (consp elem)
- (cons (car elem)
- (mapcar (lambda (elt)
- (if (consp elt) elt (list elt)))
- (cdr elem)))
- (list elem)))
- (default-value symbol)))
- :set (lambda (symbol value)
- (custom-set-default
- symbol
- (mapcar (lambda (elem)
- (if (consp elem)
- (if (cdr elem)
- (mapcar (lambda (elt)
- (if (consp elt)
- (if (cdr elt) elt (car elt))
- elt))
- elem)
- (car elem))
- elem))
- value))))
-
-(defcustom gnus-nocem-directory
- (nnheader-concat gnus-article-save-directory "NoCeM/")
- "*Directory where NoCeM files will be stored."
- :group 'gnus-nocem
- :type 'directory)
-
-(defcustom gnus-nocem-expiry-wait 15
- "*Number of days to keep NoCeM headers in the cache."
- :group 'gnus-nocem
- :type 'integer)
-
-(defcustom gnus-nocem-verifyer (if (locate-library "epg")
- 'gnus-nocem-epg-verify
- 'pgg-verify)
- "*Function called to verify that the NoCeM message is valid.
-If the function in this variable isn't bound, the message will be used
-unconditionally."
- :group 'gnus-nocem
- :version "23.1"
- :type '(radio (function-item gnus-nocem-epg-verify)
- (function-item pgg-verify)
- (function-item mc-verify)
- (function :tag "other"))
- :set (lambda (symbol value)
- (custom-set-default symbol
- (if (and (eq value 'gnus-nocem-epg-verify)
- (not (locate-library "epg")))
- 'pgg-verify
- value))))
-
-(defcustom gnus-nocem-liberal-fetch nil
- "*If t try to fetch all messages which have @@NCM in the subject.
-Otherwise don't fetch messages which have references or whose message-id
-matches a previously scanned and verified nocem message."
- :group 'gnus-nocem
- :type 'boolean)
-
-(defcustom gnus-nocem-check-article-limit 500
- "*If non-nil, the maximum number of articles to check in any NoCeM group."
- :group 'gnus-nocem
- :version "21.1"
- :type '(choice (const :tag "unlimited" nil)
- (integer 1000)))
-
-(defcustom gnus-nocem-check-from t
- "Non-nil means check for valid issuers in message bodies.
-Otherwise don't bother fetching articles unless their author matches a
-valid issuer, which is much faster if you are selective about the issuers."
- :group 'gnus-nocem
- :version "21.1"
- :type 'boolean)
-
-;;; Internal variables
-
-(defvar gnus-nocem-active nil)
-(defvar gnus-nocem-alist nil)
-(defvar gnus-nocem-touched-alist nil)
-(defvar gnus-nocem-hashtb nil)
-(defvar gnus-nocem-seen-message-ids nil)
-
-;;; Functions
-
-(defun gnus-nocem-active-file ()
- (concat (file-name-as-directory gnus-nocem-directory) "active"))
-
-(defun gnus-nocem-cache-file ()
- (concat (file-name-as-directory gnus-nocem-directory) "cache"))
-
-;;
-;; faster lookups for group names:
-;;
-
-(defvar gnus-nocem-real-group-hashtb nil
- "Real-name mappings of subscribed groups.")
-
-(defun gnus-fill-real-hashtb ()
- "Fill up a hash table with the real-name mappings from the user's active file."
- (if (hash-table-p gnus-nocem-real-group-hashtb)
- (clrhash gnus-nocem-real-group-hashtb)
- (setq gnus-nocem-real-group-hashtb (make-hash-table :test 'equal)))
- (mapcar (lambda (group)
- (setq group (gnus-group-real-name (car group)))
- (puthash group t gnus-nocem-real-group-hashtb))
- gnus-newsrc-alist))
-
-;;;###autoload
-(defun gnus-nocem-scan-groups ()
- "Scan all NoCeM groups for new NoCeM messages."
- (interactive)
- (let ((groups gnus-nocem-groups)
- (gnus-inhibit-demon t)
- group active gactive articles check-headers)
- (gnus-make-directory gnus-nocem-directory)
- ;; Load any previous NoCeM headers.
- (gnus-nocem-load-cache)
- ;; Get the group name mappings:
- (gnus-fill-real-hashtb)
- ;; Read the active file if it hasn't been read yet.
- (and (file-exists-p (gnus-nocem-active-file))
- (not gnus-nocem-active)
- (ignore-errors
- (load (gnus-nocem-active-file) t t t)))
- ;; Go through all groups and see whether new articles have
- ;; arrived.
- (while (setq group (pop groups))
- (if (not (setq gactive (gnus-activate-group group)))
- () ; This group doesn't exist.
- (setq active (nth 1 (assoc group gnus-nocem-active)))
- (when (and (not (< (cdr gactive) (car gactive))) ; Empty group.
- (or (not active)
- (< (cdr active) (cdr gactive))))
- ;; Ok, there are new articles in this group, se we fetch the
- ;; headers.
- (save-excursion
- (let ((dependencies (make-vector 10 nil))
- headers header)
- (with-temp-buffer
- (setq headers
- (if (eq 'nov
- (gnus-retrieve-headers
- (setq articles
- (gnus-uncompress-range
- (cons
- (if active (1+ (cdr active))
- (car gactive))
- (cdr gactive))))
- group))
- (gnus-get-newsgroup-headers-xover
- articles nil dependencies)
- (gnus-get-newsgroup-headers dependencies)))
- (while (setq header (pop headers))
- ;; We take a closer look on all articles that have
- ;; "@@NCM" in the subject. Unless we already read
- ;; this cross posted message. Nocem messages
- ;; are not allowed to have references, so we can
- ;; ignore scanning followups.
- (and (string-match "@@NCM" (mail-header-subject header))
- (and gnus-nocem-check-from
- (let ((case-fold-search t))
- (catch 'ok
- (mapc
- (lambda (author)
- (if (consp author)
- (setq author (car author)))
- (if (string-match
- author (mail-header-from header))
- (throw 'ok t)))
- gnus-nocem-issuers)
- nil)))
- (or gnus-nocem-liberal-fetch
- (and (or (string= "" (mail-header-references
- header))
- (null (mail-header-references header)))
- (not (member (mail-header-message-id header)
- gnus-nocem-seen-message-ids))))
- (push header check-headers)))
- (setq check-headers (last (nreverse check-headers)
- gnus-nocem-check-article-limit))
- (let ((i 0)
- (len (length check-headers)))
- (dolist (h check-headers)
- (gnus-message
- 7 "Checking article %d in %s for NoCeM (%d of %d)..."
- (mail-header-number h) group (incf i) len)
- (gnus-nocem-check-article group h)))))))
- (setq gnus-nocem-active
- (cons (list group gactive)
- (delq (assoc group gnus-nocem-active)
- gnus-nocem-active)))))
- ;; Save the results, if any.
- (gnus-nocem-save-cache)
- (gnus-nocem-save-active)))
-
-(defun gnus-nocem-check-article (group header)
- "Check whether the current article is an NCM article and that we want it."
- ;; Get the article.
- (let ((date (mail-header-date header))
- (gnus-newsgroup-name group)
- issuer b e type)
- (when (or (not date)
- (time-less-p
- (time-since (date-to-time date))
- (days-to-time gnus-nocem-expiry-wait)))
- (gnus-request-article-this-buffer (mail-header-number header) group)
- (goto-char (point-min))
- (when (re-search-forward
- "-----BEGIN PGP\\(?: SIGNED\\)? MESSAGE-----"
- nil t)
- (delete-region (point-min) (match-beginning 0)))
- (when (re-search-forward
- "-----END PGP \\(?:MESSAGE\\|SIGNATURE\\)-----\n?"
- nil t)
- (delete-region (match-end 0) (point-max)))
- (goto-char (point-min))
- ;; The article has to have proper NoCeM headers.
- (when (and (setq b (search-forward "\n@@BEGIN NCM HEADERS\n" nil t))
- (setq e (search-forward "\n@@BEGIN NCM BODY\n" nil t)))
- ;; We get the name of the issuer.
- (narrow-to-region b e)
- (setq issuer (mail-fetch-field "issuer")
- type (mail-fetch-field "type"))
- (widen)
- (if (not (gnus-nocem-message-wanted-p issuer type))
- (message "invalid NoCeM issuer: %s" issuer)
- (and (gnus-nocem-verify-issuer issuer) ; She is who she says she is.
- (gnus-nocem-enter-article) ; We gobble the message.
- (push (mail-header-message-id header) ; But don't come back for
- gnus-nocem-seen-message-ids))))))) ; second helpings.
-
-(defun gnus-nocem-message-wanted-p (issuer type)
- (let ((issuers gnus-nocem-issuers)
- wanted conditions condition)
- (cond
- ;; Do the quick check first.
- ((member issuer issuers)
- t)
- ((setq conditions (cdr (assoc issuer issuers)))
- ;; Check whether we want this type.
- (while (setq condition (pop conditions))
- (cond
- ((stringp condition)
- (when (string-match condition type)
- (setq wanted t)))
- ((and (consp condition)
- (eq (car condition) 'not)
- (stringp (cadr condition)))
- (when (string-match (cadr condition) type)
- (setq wanted nil)))
- (t
- (error "Invalid NoCeM condition: %S" condition))))
- wanted))))
-
-(defun gnus-nocem-verify-issuer (person)
- "Verify using PGP that the canceler is who she says she is."
- (if (functionp gnus-nocem-verifyer)
- (ignore-errors
- (funcall gnus-nocem-verifyer))
- ;; If we don't have Mailcrypt, then we use the message anyway.
- t))
-
-(defun gnus-nocem-enter-article ()
- "Enter the current article into the NoCeM cache."
- (goto-char (point-min))
- (let ((b (search-forward "\n@@BEGIN NCM BODY\n" nil t))
- (e (search-forward "\n@@END NCM BODY\n" nil t))
- (buf (current-buffer))
- ncm id group)
- (when (and b e)
- (narrow-to-region b (1+ (match-beginning 0)))
- (goto-char (point-min))
- (while (search-forward "\t" nil t)
- (cond
- ((not (ignore-errors
- (setq group (gnus-group-real-name (symbol-name (read buf))))
- (gethash group gnus-nocem-real-group-hashtb)))
- ;; An error.
- )
- (t
- ;; Valid group.
- (beginning-of-line)
- (while (eq (char-after) ?\t)
- (forward-line -1))
- (setq id (buffer-substring (point) (1- (search-forward "\t"))))
- (unless (if (hash-table-p gnus-nocem-hashtb)
- (gethash id gnus-nocem-hashtb)
- (setq gnus-nocem-hashtb (make-hash-table :test 'equal))
- nil)
- ;; only store if not already present
- (puthash id t gnus-nocem-hashtb)
- (push id ncm))
- (forward-line 1)
- (while (eq (char-after) ?\t)
- (forward-line 1)))))
- (when ncm
- (setq gnus-nocem-touched-alist t)
- (push (cons (let ((time (current-time))) (setcdr (cdr time) nil) time)
- ncm)
- gnus-nocem-alist))
- t)))
-
-;;;###autoload
-(defun gnus-nocem-load-cache ()
- "Load the NoCeM cache."
- (interactive)
- (unless gnus-nocem-alist
- ;; The buffer doesn't exist, so we create it and load the NoCeM
- ;; cache.
- (when (file-exists-p (gnus-nocem-cache-file))
- (load (gnus-nocem-cache-file) t t t)
- (gnus-nocem-alist-to-hashtb))))
-
-(defun gnus-nocem-save-cache ()
- "Save the NoCeM cache."
- (when (and gnus-nocem-alist
- gnus-nocem-touched-alist)
- (with-temp-file (gnus-nocem-cache-file)
- (gnus-prin1 `(setq gnus-nocem-alist ',gnus-nocem-alist)))
- (setq gnus-nocem-touched-alist nil)))
-
-(defun gnus-nocem-save-active ()
- "Save the NoCeM active file."
- (with-temp-file (gnus-nocem-active-file)
- (gnus-prin1 `(setq gnus-nocem-active ',gnus-nocem-active))))
-
-(defun gnus-nocem-alist-to-hashtb ()
- "Create a hashtable from the Message-IDs we have."
- (let* ((alist gnus-nocem-alist)
- (pprev (cons nil alist))
- (prev pprev)
- (expiry (days-to-time gnus-nocem-expiry-wait))
- entry)
- (if (hash-table-p gnus-nocem-hashtb)
- (clrhash gnus-nocem-hashtb)
- (setq gnus-nocem-hashtb (make-hash-table :test 'equal)))
- (while (setq entry (car alist))
- (if (not (time-less-p (time-since (car entry)) expiry))
- ;; This entry has expired, so we remove it.
- (setcdr prev (cdr alist))
- (setq prev alist)
- ;; This is ok, so we enter it into the hashtable.
- (setq entry (cdr entry))
- (while entry
- (puthash (car entry) t gnus-nocem-hashtb)
- (setq entry (cdr entry))))
- (setq alist (cdr alist)))))
-
-(gnus-add-shutdown 'gnus-nocem-close 'gnus)
-
-(defun gnus-nocem-close ()
- "Clear internal NoCeM variables."
- (setq gnus-nocem-alist nil
- gnus-nocem-hashtb nil
- gnus-nocem-active nil
- gnus-nocem-touched-alist nil
- gnus-nocem-seen-message-ids nil
- gnus-nocem-real-group-hashtb nil))
-
-(defun gnus-nocem-unwanted-article-p (id)
- "Say whether article ID in the current group is wanted."
- (and gnus-nocem-hashtb
- (gethash id gnus-nocem-hashtb)))
-
-(autoload 'epg-make-context "epg")
-(eval-when-compile
- (autoload 'epg-verify-string "epg")
- (autoload 'epg-context-result-for "epg")
- (autoload 'epg-signature-status "epg"))
-
-(defun gnus-nocem-epg-verify ()
- "Return t if EasyPG verifies a signed message in the current buffer."
- (let ((context (epg-make-context 'OpenPGP))
- result)
- (epg-verify-string context (buffer-string))
- (and (setq result (epg-context-result-for context 'verify))
- (not (cdr result))
- (eq (epg-signature-status (car result)) 'good))))
-
-(provide 'gnus-nocem)
-
-;;; gnus-nocem.el ends here
diff --git a/lisp/gnus/gnus-srvr.el b/lisp/gnus/gnus-srvr.el
index 2966212de69..11164a8df6c 100644
--- a/lisp/gnus/gnus-srvr.el
+++ b/lisp/gnus/gnus-srvr.el
@@ -28,6 +28,7 @@
(eval-when-compile (require 'cl))
(require 'gnus)
+(require 'gnus-start)
(require 'gnus-spec)
(require 'gnus-group)
(require 'gnus-int)
@@ -547,6 +548,7 @@ The following commands are available:
(gnus-server-list-servers))
(defun gnus-server-copy-server (from to)
+ "Copy a server definiton to a new name."
(interactive
(list
(or (gnus-server-server-name)
@@ -643,6 +645,30 @@ The following commands are available:
(defvar gnus-browse-menu-hook nil
"*Hook run after the creation of the browse mode menu.")
+(defcustom gnus-browse-subscribe-newsgroup-method
+ 'gnus-subscribe-alphabetically
+ "Function(s) called when subscribing groups in the Browse Server Buffer
+A few pre-made functions are supplied: `gnus-subscribe-randomly'
+inserts new groups at the beginning of the list of groups;
+`gnus-subscribe-alphabetically' inserts new groups in strict
+alphabetic order; `gnus-subscribe-hierarchically' inserts new groups
+in hierarchical newsgroup order; `gnus-subscribe-interactively' asks
+for your decision; `gnus-subscribe-killed' kills all new groups;
+`gnus-subscribe-zombies' will make all new groups into zombies;
+`gnus-subscribe-topics' will enter groups into the topics that
+claim them."
+ :version "24.1"
+ :group 'gnus-server
+ :type '(radio (function-item gnus-subscribe-randomly)
+ (function-item gnus-subscribe-alphabetically)
+ (function-item gnus-subscribe-hierarchically)
+ (function-item gnus-subscribe-interactively)
+ (function-item gnus-subscribe-killed)
+ (function-item gnus-subscribe-zombies)
+ (function-item gnus-subscribe-topics)
+ function
+ (repeat function)))
+
(defvar gnus-browse-mode-hook nil)
(defvar gnus-browse-mode-map nil)
(put 'gnus-browse-mode 'mode-class 'special)
@@ -890,7 +916,9 @@ If NUMBER, fetch this number of articles."
(gnus-browse-next-group (- n)))
(defun gnus-browse-unsubscribe-current-group (arg)
- "(Un)subscribe to the next ARG groups."
+ "(Un)subscribe to the next ARG groups.
+The variable `gnus-browse-subscribe-newsgroup-method' determines
+how new groups will be entered into the group buffer."
(interactive "p")
(when (eobp)
(error "No group at current line"))
@@ -939,22 +967,24 @@ If NUMBER, fetch this number of articles."
;; subscribe to it.
(if (gnus-ephemeral-group-p group)
(gnus-kill-ephemeral-group group))
- ;; We need to discern between killed/zombie groups and
- ;; just unsubscribed ones.
- (gnus-group-change-level
- (or (gnus-group-entry group)
- (list t group gnus-level-default-subscribed
- nil nil (if (gnus-server-equal
- gnus-browse-current-method "native")
- nil
- (gnus-method-simplify
- gnus-browse-current-method))))
- gnus-level-default-subscribed (gnus-group-level group)
- (and (car (nth 1 gnus-newsrc-alist))
- (gnus-group-entry (car (nth 1 gnus-newsrc-alist))))
- (null (gnus-group-entry group)))
+ (let ((entry (gnus-group-entry group)))
+ (if entry
+ ;; Just change the subscription level if it is an
+ ;; unsubscribed group.
+ (gnus-group-change-level entry
+ gnus-level-default-subscribed)
+ ;; If it is a killed group or a zombie, feed it to the
+ ;; mechanism for new group subscription.
+ (gnus-call-subscribe-functions
+ gnus-browse-subscribe-newsgroup-method
+ group)))
(delete-char 1)
- (insert ? ))
+ (insert (let ((lvl (gnus-group-level group)))
+ (cond
+ ((< lvl gnus-level-unsubscribed) ? )
+ ((< lvl gnus-level-zombie) ?U)
+ ((< lvl gnus-level-killed) ?Z)
+ (t ?K)))))
(gnus-group-change-level
group gnus-level-unsubscribed gnus-level-default-subscribed)
(delete-char 1)
diff --git a/lisp/gnus/gnus-start.el b/lisp/gnus/gnus-start.el
index 5aec3e7b729..68f26ea143b 100644
--- a/lisp/gnus/gnus-start.el
+++ b/lisp/gnus/gnus-start.el
@@ -1063,15 +1063,6 @@ If LEVEL is non-nil, the news will be set up at level LEVEL."
(gnus-server-opened gnus-select-method))
(gnus-check-bogus-newsgroups))
- ;; We might read in new NoCeM messages here.
- (when (and (not dont-connect)
- gnus-use-nocem
- (or (and (numberp gnus-use-nocem)
- (numberp level)
- (>= level gnus-use-nocem))
- (not level)))
- (gnus-nocem-scan-groups))
-
;; Read any slave files.
(gnus-master-read-slave-newsrc)
@@ -1767,8 +1758,10 @@ If SCAN, request a scan of that group as well."
(not (gnus-method-denied-p method)))
(unless (gnus-server-opened method)
(gnus-open-server method))
- (when (gnus-check-backend-function
- 'retrieve-group-data-early (car method))
+ (when (and
+ (gnus-server-opened method)
+ (gnus-check-backend-function
+ 'retrieve-group-data-early (car method)))
(when (gnus-check-backend-function 'request-scan (car method))
(gnus-request-scan nil method))
(setcar (nthcdr 3 elem)
diff --git a/lisp/gnus/gnus-sum.el b/lisp/gnus/gnus-sum.el
index 0af75829bd3..195c7249778 100644
--- a/lisp/gnus/gnus-sum.el
+++ b/lisp/gnus/gnus-sum.el
@@ -2047,6 +2047,7 @@ increase the score of each group you read."
"e" gnus-summary-end-of-article
"^" gnus-summary-refer-parent-article
"r" gnus-summary-refer-parent-article
+ "C" gnus-summary-show-complete-article
"D" gnus-summary-enter-digest-group
"R" gnus-summary-refer-references
"T" gnus-summary-refer-thread
@@ -8645,8 +8646,7 @@ fetch-old-headers verbiage, and so on."
(null gnus-summary-expunge-below)
(not (eq gnus-build-sparse-threads 'some))
(not (eq gnus-build-sparse-threads 'more))
- (null gnus-thread-expunge-below)
- (not gnus-use-nocem)))
+ (null gnus-thread-expunge-below)))
(push gnus-newsgroup-limit gnus-newsgroup-limits)
(setq gnus-newsgroup-limit nil)
(mapatoms
@@ -8729,14 +8729,7 @@ fetch-old-headers verbiage, and so on."
t)
;; Do the `display' group parameter.
(and gnus-newsgroup-display
- (not (funcall gnus-newsgroup-display)))
- ;; Check NoCeM things.
- (when (and gnus-use-nocem
- (gnus-nocem-unwanted-article-p
- (mail-header-id (car thread))))
- (setq gnus-newsgroup-unreads
- (delq number gnus-newsgroup-unreads))
- t)))
+ (not (funcall gnus-newsgroup-display)))))
;; Nope, invisible article.
0
;; Ok, this article is to be visible, so we add it to the limit
@@ -9357,6 +9350,18 @@ to save in."
(ps-spool-buffer)))))
(kill-buffer buffer))))
+(defun gnus-summary-show-complete-article ()
+ "Show a complete version of the current article.
+This is only useful if you're looking at a partial version of the
+article currently."
+ (interactive)
+ (let ((gnus-keep-backlog nil)
+ (gnus-use-cache nil)
+ (gnus-agent nil)
+ (gnus-fetch-partial-articles nil))
+ (gnus-flush-original-article-buffer)
+ (gnus-summary-show-article)))
+
(defun gnus-summary-show-article (&optional arg)
"Force redisplaying of the current article.
If ARG (the prefix) is a number, show the article with the charset
diff --git a/lisp/gnus/gnus.el b/lisp/gnus/gnus.el
index c3bf47b9533..0c01d599cfc 100644
--- a/lisp/gnus/gnus.el
+++ b/lisp/gnus/gnus.el
@@ -308,11 +308,6 @@ be set in `.emacs' instead."
:group 'gnus-start
:type 'boolean)
-(defcustom gnus-play-startup-jingle nil
- "If non-nil, play the Gnus jingle at startup."
- :group 'gnus-start
- :type 'boolean)
-
(unless (fboundp 'gnus-group-remove-excess-properties)
(defalias 'gnus-group-remove-excess-properties 'ignore))
@@ -960,8 +955,6 @@ be set in `.emacs' instead."
(defvar gnus-group-buffer "*Group*")
-(autoload 'gnus-play-jingle "gnus-audio")
-
(defface gnus-splash
'((((class color)
(background dark))
@@ -984,9 +977,7 @@ be set in `.emacs' instead."
(erase-buffer)
(unless gnus-inhibit-startup-message
(gnus-group-startup-message)
- (sit-for 0)
- (when gnus-play-startup-jingle
- (gnus-play-jingle))))))
+ (sit-for 0)))))
(defun gnus-indent-rigidly (start end arg)
"Indent rigidly using only spaces and no tabs."
@@ -1580,25 +1571,6 @@ articles. This is not a good idea."
(sexp :format "all"
:value t)))
-(defcustom gnus-use-nocem nil
- "*If non-nil, Gnus will read NoCeM cancel messages.
-You can also set this variable to a positive number as a group level.
-In that case, Gnus scans NoCeM messages when checking new news if this
-value is not exceeding a group level that you specify as the prefix
-argument to some commands, e.g. `gnus', `gnus-group-get-new-news', etc.
-Otherwise, Gnus does not scan NoCeM messages if you specify a group
-level to those commands."
- :group 'gnus-meta
- :type '(choice
- (const :tag "off" nil)
- (const :tag "on" t)
- (list :convert-widget
- (lambda (widget)
- (list 'integer :tag "group level"
- :value (if (boundp 'gnus-level-default-subscribed)
- gnus-level-default-subscribed
- 3))))))
-
(defcustom gnus-suppress-duplicates nil
"*If non-nil, Gnus will mark duplicate copies of the same article as read."
:group 'gnus-meta
@@ -2813,13 +2785,12 @@ gnus-registry.el will populate this if it's loaded.")
rmail-summary-exists rmail-select-summary)
;; Only used in gnus-util, which has an autoload.
("rmailsum" rmail-update-summary)
- ("gnus-audio" :interactive t gnus-audio-play)
("gnus-xmas" gnus-xmas-splash)
("score-mode" :interactive t gnus-score-mode)
("gnus-mh" gnus-summary-save-article-folder
gnus-Folder-save-name gnus-folder-save-name)
("gnus-mh" :interactive t gnus-summary-save-in-folder)
- ("gnus-demon" gnus-demon-add-nocem gnus-demon-add-scanmail
+ ("gnus-demon" gnus-demon-add-scanmail
gnus-demon-add-rescan gnus-demon-add-scan-timestamps
gnus-demon-add-disconnection gnus-demon-add-handler
gnus-demon-remove-handler)
@@ -2830,8 +2801,6 @@ gnus-registry.el will populate this if it's loaded.")
gnus-face-from-file)
("gnus-salt" gnus-highlight-selected-tree gnus-possibly-generate-tree
gnus-tree-open gnus-tree-close gnus-carpal-setup-buffer)
- ("gnus-nocem" gnus-nocem-scan-groups gnus-nocem-close
- gnus-nocem-unwanted-article-p)
("gnus-srvr" gnus-enter-server-buffer gnus-server-set-info
gnus-server-server-name)
("gnus-srvr" gnus-browse-foreign-server)
@@ -4395,7 +4364,7 @@ prompt the user for the name of an NNTP server to use."
;; When using the development version of Gnus, load the gnus-load
;; file.
(unless (string-match "^Gnus" gnus-version)
- (load "gnus-load"))
+ (load "gnus-load" nil t))
(unless (byte-code-function-p (symbol-function 'gnus))
(message "You should byte-compile Gnus")
(sit-for 2))
diff --git a/lisp/gnus/mm-decode.el b/lisp/gnus/mm-decode.el
index 948fc08135d..f773c2fea68 100644
--- a/lisp/gnus/mm-decode.el
+++ b/lisp/gnus/mm-decode.el
@@ -1147,13 +1147,15 @@ in HANDLE."
;; time to adjust it, since we know at this point that it should
;; be unibyte.
`(let* ((handle ,handle))
- (with-temp-buffer
- (mm-disable-multibyte)
- (insert-buffer-substring (mm-handle-buffer handle))
- (mm-decode-content-transfer-encoding
- (mm-handle-encoding handle)
- (mm-handle-media-type handle))
- ,@forms)))
+ (when (and (mm-handle-buffer handle)
+ (buffer-name (mm-handle-buffer handle)))
+ (with-temp-buffer
+ (mm-disable-multibyte)
+ (insert-buffer-substring (mm-handle-buffer handle))
+ (mm-decode-content-transfer-encoding
+ (mm-handle-encoding handle)
+ (mm-handle-media-type handle))
+ ,@forms))))
(put 'mm-with-part 'lisp-indent-function 1)
(put 'mm-with-part 'edebug-form-spec '(body))
@@ -1246,9 +1248,13 @@ PROMPT overrides the default one used to ask user for a file name."
(setq filename (gnus-map-function mm-file-name-rewrite-functions
(file-name-nondirectory filename))))
(setq file
- (read-file-name (or prompt "Save MIME part to: ")
+ (read-file-name (or prompt
+ (format "Save MIME part to (default %s): "
+ (or filename "")))
(or mm-default-directory default-directory)
- nil nil (or filename "")))
+ (or filename "")))
+ (when (file-directory-p file)
+ (setq file (expand-file-name filename file)))
(setq mm-default-directory (file-name-directory file))
(and (or (not (file-exists-p file))
(yes-or-no-p (format "File %s already exists; overwrite? "
diff --git a/lisp/gnus/mml1991.el b/lisp/gnus/mml1991.el
index b73162ff131..22eb7b66829 100644
--- a/lisp/gnus/mml1991.el
+++ b/lisp/gnus/mml1991.el
@@ -57,8 +57,6 @@
(defvar mml1991-function-alist
'((mailcrypt mml1991-mailcrypt-sign
mml1991-mailcrypt-encrypt)
- (gpg mml1991-gpg-sign
- mml1991-gpg-encrypt)
(pgg mml1991-pgg-sign
mml1991-pgg-encrypt)
(epg mml1991-epg-sign
@@ -168,99 +166,6 @@ Whether the passphrase is cached at all is controlled by
(insert-buffer-substring cipher)
(goto-char (point-max))))))
-;;; gpg wrapper
-
-(autoload 'gpg-sign-cleartext "gpg")
-
-(declare-function gpg-sign-encrypt "ext:gpg"
- (plaintext ciphertext result recipients &optional
- passphrase sign-with-key armor textmode))
-(declare-function gpg-encrypt "ext:gpg"
- (plaintext ciphertext result recipients &optional
- passphrase armor textmode))
-
-(defun mml1991-gpg-sign (cont)
- (let ((text (current-buffer))
- headers signature
- (result-buffer (get-buffer-create "*GPG Result*")))
- ;; Save MIME Content[^ ]+: headers from signing
- (goto-char (point-min))
- (while (looking-at "^Content[^ ]+:") (forward-line))
- (unless (bobp)
- (setq headers (buffer-string))
- (delete-region (point-min) (point)))
- (goto-char (point-max))
- (unless (bolp)
- (insert "\n"))
- (quoted-printable-decode-region (point-min) (point-max))
- (with-temp-buffer
- (unless (gpg-sign-cleartext text (setq signature (current-buffer))
- result-buffer
- nil
- (message-options-get 'message-sender))
- (unless (> (point-max) (point-min))
- (pop-to-buffer result-buffer)
- (error "Sign error")))
- (goto-char (point-min))
- (while (re-search-forward "\r+$" nil t)
- (replace-match "" t t))
- (quoted-printable-encode-region (point-min) (point-max))
- (set-buffer text)
- (delete-region (point-min) (point-max))
- (if headers (insert headers))
- (insert "\n")
- (insert-buffer-substring signature)
- (goto-char (point-max)))))
-
-(defun mml1991-gpg-encrypt (cont &optional sign)
- (let ((text (current-buffer))
- cipher
- (result-buffer (get-buffer-create "*GPG Result*")))
- ;; Strip MIME Content[^ ]: headers since it will be ASCII ARMORED
- (goto-char (point-min))
- (while (looking-at "^Content[^ ]+:") (forward-line))
- (unless (bobp)
- (delete-region (point-min) (point)))
- (mm-with-unibyte-current-buffer
- (with-temp-buffer
- (inline (mm-disable-multibyte))
- (flet ((gpg-encrypt-func
- (sign plaintext ciphertext result recipients &optional
- passphrase sign-with-key armor textmode)
- (if sign
- (gpg-sign-encrypt
- plaintext ciphertext result recipients passphrase
- sign-with-key armor textmode)
- (gpg-encrypt
- plaintext ciphertext result recipients passphrase
- armor textmode))))
- (unless (gpg-encrypt-func
- sign
- text (setq cipher (current-buffer))
- result-buffer
- (split-string
- (or
- (message-options-get 'message-recipients)
- (message-options-set 'message-recipients
- (read-string "Recipients: ")))
- "[ \f\t\n\r\v,]+")
- nil
- (message-options-get 'message-sender)
- t t) ; armor & textmode
- (unless (> (point-max) (point-min))
- (pop-to-buffer result-buffer)
- (error "Encrypt error"))))
- (goto-char (point-min))
- (while (re-search-forward "\r+$" nil t)
- (replace-match "" t t))
- (set-buffer text)
- (delete-region (point-min) (point-max))
- ;;(insert "Content-Type: application/pgp-encrypted\n\n")
- ;;(insert "Version: 1\n\n")
- (insert "\n")
- (insert-buffer-substring cipher)
- (goto-char (point-max))))))
-
;; pgg wrapper
(defvar pgg-default-user-id)
diff --git a/lisp/gnus/mml2015.el b/lisp/gnus/mml2015.el
index 1002f24ea82..391517f38ba 100644
--- a/lisp/gnus/mml2015.el
+++ b/lisp/gnus/mml2015.el
@@ -63,11 +63,6 @@
(require 'pgg)))
(and (fboundp 'pgg-sign-region)
'pgg))
- (progn
- (ignore-errors
- (require 'gpg))
- (and (fboundp 'gpg-sign-detached)
- 'gpg))
(progn (ignore-errors
(load "mc-toplev"))
(and (fboundp 'mc-encrypt-generic)
@@ -75,7 +70,7 @@
(fboundp 'mc-cleanup-recipient-headers)
'mailcrypt)))
"The package used for PGP/MIME.
-Valid packages include `epg', `pgg', `gpg' and `mailcrypt'.")
+Valid packages include `epg', `pgg' and `mailcrypt'.")
;; Something is not RFC2015.
(defvar mml2015-function-alist
@@ -85,24 +80,18 @@ Valid packages include `epg', `pgg', `gpg' and `mailcrypt'.")
mml2015-mailcrypt-decrypt
mml2015-mailcrypt-clear-verify
mml2015-mailcrypt-clear-decrypt)
- (gpg mml2015-gpg-sign
- mml2015-gpg-encrypt
- mml2015-gpg-verify
- mml2015-gpg-decrypt
- mml2015-gpg-clear-verify
- mml2015-gpg-clear-decrypt)
- (pgg mml2015-pgg-sign
- mml2015-pgg-encrypt
- mml2015-pgg-verify
- mml2015-pgg-decrypt
- mml2015-pgg-clear-verify
- mml2015-pgg-clear-decrypt)
- (epg mml2015-epg-sign
- mml2015-epg-encrypt
- mml2015-epg-verify
- mml2015-epg-decrypt
- mml2015-epg-clear-verify
- mml2015-epg-clear-decrypt))
+ (pgg mml2015-pgg-sign
+ mml2015-pgg-encrypt
+ mml2015-pgg-verify
+ mml2015-pgg-decrypt
+ mml2015-pgg-clear-verify
+ mml2015-pgg-clear-decrypt)
+ (epg mml2015-epg-sign
+ mml2015-epg-encrypt
+ mml2015-epg-verify
+ mml2015-epg-decrypt
+ mml2015-epg-clear-verify
+ mml2015-epg-clear-decrypt))
"Alist of PGP/MIME functions.")
(defvar mml2015-result-buffer nil)
@@ -148,7 +137,7 @@ Whether the passphrase is cached at all is controlled by
;; Extract plaintext from cleartext signature. IMO, this kind of task
;; should be done by GnuPG rather than Elisp, but older PGP backends
-;; (such as Mailcrypt, PGG, and gpg.el) discard the output from GnuPG.
+;; (such as Mailcrypt, and PGG) discard the output from GnuPG.
(defun mml2015-extract-cleartext-signature ()
;; Daiki Ueno in
;; <54a15d860801080142l70b95d7dkac4bf51a86196011@mail.gmail.com>: ``I still
@@ -234,6 +223,58 @@ Whether the passphrase is cached at all is controlled by
handles
(list handles)))))
+(defun mml2015-gpg-pretty-print-fpr (fingerprint)
+ (let* ((result "")
+ (fpr-length (string-width fingerprint))
+ (n-slice 0)
+ slice)
+ (setq fingerprint (string-to-list fingerprint))
+ (while fingerprint
+ (setq fpr-length (- fpr-length 4))
+ (setq slice (butlast fingerprint fpr-length))
+ (setq fingerprint (nthcdr 4 fingerprint))
+ (setq n-slice (1+ n-slice))
+ (setq result
+ (concat
+ result
+ (case n-slice
+ (1 slice)
+ (otherwise (concat " " slice))))))
+ result))
+
+(defun mml2015-gpg-extract-signature-details ()
+ (goto-char (point-min))
+ (let* ((expired (re-search-forward
+ "^\\[GNUPG:\\] SIGEXPIRED$"
+ nil t))
+ (signer (and (re-search-forward
+ "^\\[GNUPG:\\] GOODSIG \\([0-9A-Za-z]*\\) \\(.*\\)$"
+ nil t)
+ (cons (match-string 1) (match-string 2))))
+ (fprint (and (re-search-forward
+ "^\\[GNUPG:\\] VALIDSIG \\([0-9a-zA-Z]*\\) "
+ nil t)
+ (match-string 1)))
+ (trust (and (re-search-forward
+ "^\\[GNUPG:\\] \\(TRUST_.*\\)$"
+ nil t)
+ (match-string 1)))
+ (trust-good-enough-p
+ (cdr (assoc trust mml2015-unabbrev-trust-alist))))
+ (cond ((and signer fprint)
+ (concat (cdr signer)
+ (unless trust-good-enough-p
+ (concat "\nUntrusted, Fingerprint: "
+ (mml2015-gpg-pretty-print-fpr fprint)))
+ (when expired
+ (format "\nWARNING: Signature from expired key (%s)"
+ (car signer)))))
+ ((re-search-forward
+ "^\\(gpg: \\)?Good signature from \"\\(.*\\)\"$" nil t)
+ (match-string 2))
+ (t
+ "From unknown user"))))
+
(defun mml2015-mailcrypt-clear-decrypt ()
(let (result)
(setq result
@@ -446,280 +487,6 @@ Whether the passphrase is cached at all is controlled by
(insert (format "--%s--\n" boundary))
(goto-char (point-max))))
-;;; gpg wrapper
-
-(autoload 'gpg-decrypt "gpg")
-(autoload 'gpg-verify "gpg")
-(autoload 'gpg-verify-cleartext "gpg")
-(autoload 'gpg-sign-detached "gpg")
-(autoload 'gpg-sign-encrypt "gpg")
-(autoload 'gpg-encrypt "gpg")
-(autoload 'gpg-passphrase-read "gpg")
-
-(defun mml2015-gpg-passphrase ()
- (or (message-options-get 'gpg-passphrase)
- (message-options-set 'gpg-passphrase (gpg-passphrase-read))))
-
-(defun mml2015-gpg-decrypt-1 ()
- (let ((cipher (current-buffer)) plain result)
- (if (with-temp-buffer
- (prog1
- (gpg-decrypt cipher (setq plain (current-buffer))
- mml2015-result-buffer nil)
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details
- (with-current-buffer mml2015-result-buffer
- (buffer-string)))
- (set-buffer cipher)
- (erase-buffer)
- (insert-buffer-substring plain)
- (goto-char (point-min))
- (while (search-forward "\r\n" nil t)
- (replace-match "\n" t t))))
- '(t)
- ;; Some wrong with the return value, check plain text buffer.
- (if (> (point-max) (point-min))
- '(t)
- nil))))
-
-(defun mml2015-gpg-decrypt (handle ctl)
- (let ((mml2015-decrypt-function 'mml2015-gpg-decrypt-1))
- (mml2015-mailcrypt-decrypt handle ctl)))
-
-(defun mml2015-gpg-clear-decrypt ()
- (let (result)
- (setq result (mml2015-gpg-decrypt-1))
- (if (car result)
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "OK")
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Failed"))))
-
-(defun mml2015-gpg-pretty-print-fpr (fingerprint)
- (let* ((result "")
- (fpr-length (string-width fingerprint))
- (n-slice 0)
- slice)
- (setq fingerprint (string-to-list fingerprint))
- (while fingerprint
- (setq fpr-length (- fpr-length 4))
- (setq slice (butlast fingerprint fpr-length))
- (setq fingerprint (nthcdr 4 fingerprint))
- (setq n-slice (1+ n-slice))
- (setq result
- (concat
- result
- (case n-slice
- (1 slice)
- (otherwise (concat " " slice))))))
- result))
-
-(defun mml2015-gpg-extract-signature-details ()
- (goto-char (point-min))
- (let* ((expired (re-search-forward
- "^\\[GNUPG:\\] SIGEXPIRED$"
- nil t))
- (signer (and (re-search-forward
- "^\\[GNUPG:\\] GOODSIG \\([0-9A-Za-z]*\\) \\(.*\\)$"
- nil t)
- (cons (match-string 1) (match-string 2))))
- (fprint (and (re-search-forward
- "^\\[GNUPG:\\] VALIDSIG \\([0-9a-zA-Z]*\\) "
- nil t)
- (match-string 1)))
- (trust (and (re-search-forward
- "^\\[GNUPG:\\] \\(TRUST_.*\\)$"
- nil t)
- (match-string 1)))
- (trust-good-enough-p
- (cdr (assoc trust mml2015-unabbrev-trust-alist))))
- (cond ((and signer fprint)
- (concat (cdr signer)
- (unless trust-good-enough-p
- (concat "\nUntrusted, Fingerprint: "
- (mml2015-gpg-pretty-print-fpr fprint)))
- (when expired
- (format "\nWARNING: Signature from expired key (%s)"
- (car signer)))))
- ((re-search-forward
- "^\\(gpg: \\)?Good signature from \"\\(.*\\)\"$" nil t)
- (match-string 2))
- (t
- "From unknown user"))))
-
-(defun mml2015-gpg-verify (handle ctl)
- (catch 'error
- (let (part message signature info-is-set-p)
- (unless (setq part (mm-find-raw-part-by-type
- ctl (or (mm-handle-multipart-ctl-parameter
- ctl 'protocol)
- "application/pgp-signature")
- t))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Corrupted")
- (throw 'error handle))
- (with-temp-buffer
- (setq message (current-buffer))
- (insert part)
- ;; Convert <LF> to <CR><LF> in signed text. If --textmode is
- ;; specified when signing, the conversion is not necessary.
- (goto-char (point-min))
- (end-of-line)
- (while (not (eobp))
- (unless (eq (char-before) ?\r)
- (insert "\r"))
- (forward-line)
- (end-of-line))
- (with-temp-buffer
- (setq signature (current-buffer))
- (unless (setq part (mm-find-part-by-type
- (cdr handle) "application/pgp-signature" nil t))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Corrupted")
- (throw 'error handle))
- (mm-insert-part part)
- (unless (condition-case err
- (prog1
- (gpg-verify message signature mml2015-result-buffer)
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details
- (with-current-buffer mml2015-result-buffer
- (buffer-string))))
- (error
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (mml2015-format-error err))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Error.")
- (setq info-is-set-p t)
- nil)
- (quit
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details "Quit.")
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Quit.")
- (setq info-is-set-p t)
- nil))
- (unless info-is-set-p
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Failed"))
- (throw 'error handle)))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info
- (with-current-buffer mml2015-result-buffer
- (mml2015-gpg-extract-signature-details))))
- handle)))
-
-(defun mml2015-gpg-clear-verify ()
- (if (condition-case err
- (prog1
- (gpg-verify-cleartext (current-buffer) mml2015-result-buffer)
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details
- (with-current-buffer mml2015-result-buffer
- (buffer-string))))
- (error
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details (mml2015-format-error err))
- nil)
- (quit
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-details "Quit.")
- nil))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info
- (with-current-buffer mml2015-result-buffer
- (mml2015-gpg-extract-signature-details)))
- (mm-set-handle-multipart-parameter
- mm-security-handle 'gnus-info "Failed"))
- (mml2015-extract-cleartext-signature))
-
-(defun mml2015-gpg-sign (cont)
- (let ((boundary (mml-compute-boundary cont))
- (text (current-buffer)) signature)
- (goto-char (point-max))
- (unless (bolp)
- (insert "\n"))
- (with-temp-buffer
- (unless (gpg-sign-detached text (setq signature (current-buffer))
- mml2015-result-buffer
- nil
- (message-options-get 'message-sender)
- t t) ; armor & textmode
- (unless (> (point-max) (point-min))
- (pop-to-buffer mml2015-result-buffer)
- (error "Sign error")))
- (goto-char (point-min))
- (while (re-search-forward "\r+$" nil t)
- (replace-match "" t t))
- (set-buffer text)
- (goto-char (point-min))
- (insert (format "Content-Type: multipart/signed; boundary=\"%s\";\n"
- boundary))
- ;;; FIXME: what is the micalg?
- (insert "\tmicalg=pgp-sha1; protocol=\"application/pgp-signature\"\n")
- (insert (format "\n--%s\n" boundary))
- (goto-char (point-max))
- (insert (format "\n--%s\n" boundary))
- (insert "Content-Type: application/pgp-signature\n\n")
- (insert-buffer-substring signature)
- (goto-char (point-max))
- (insert (format "--%s--\n" boundary))
- (goto-char (point-max)))))
-
-(defun mml2015-gpg-encrypt (cont &optional sign)
- (let ((boundary (mml-compute-boundary cont))
- (text (current-buffer))
- cipher)
- (mm-with-unibyte-current-buffer
- (with-temp-buffer
- (mm-disable-multibyte)
- ;; set up a function to call the correct gpg encrypt routine
- ;; with the right arguments. (FIXME: this should be done
- ;; differently.)
- (flet ((gpg-encrypt-func
- (sign plaintext ciphertext result recipients &optional
- passphrase sign-with-key armor textmode)
- (if sign
- (gpg-sign-encrypt
- plaintext ciphertext result recipients passphrase
- sign-with-key armor textmode)
- (gpg-encrypt
- plaintext ciphertext result recipients passphrase
- armor textmode))))
- (unless (gpg-encrypt-func
- sign ; passed in when using signencrypt
- text (setq cipher (current-buffer))
- mml2015-result-buffer
- (split-string
- (or
- (message-options-get 'message-recipients)
- (message-options-set 'message-recipients
- (read-string "Recipients: ")))
- "[ \f\t\n\r\v,]+")
- nil
- (message-options-get 'message-sender)
- t t) ; armor & textmode
- (unless (> (point-max) (point-min))
- (pop-to-buffer mml2015-result-buffer)
- (error "Encrypt error"))))
- (goto-char (point-min))
- (while (re-search-forward "\r+$" nil t)
- (replace-match "" t t))
- (set-buffer text)
- (delete-region (point-min) (point-max))
- (insert (format "Content-Type: multipart/encrypted; boundary=\"%s\";\n"
- boundary))
- (insert "\tprotocol=\"application/pgp-encrypted\"\n\n")
- (insert (format "--%s\n" boundary))
- (insert "Content-Type: application/pgp-encrypted\n\n")
- (insert "Version: 1\n\n")
- (insert (format "--%s\n" boundary))
- (insert "Content-Type: application/octet-stream\n\n")
- (insert-buffer-substring cipher)
- (goto-char (point-max))
- (insert (format "--%s--\n" boundary))
- (goto-char (point-max))))))
-
;;; pgg wrapper
(defvar pgg-default-user-id)
diff --git a/lisp/gnus/nndoc.el b/lisp/gnus/nndoc.el
index d6d455f078f..2eeaeba0512 100644
--- a/lisp/gnus/nndoc.el
+++ b/lisp/gnus/nndoc.el
@@ -64,9 +64,6 @@ from the document.")
(body-end . "")
(file-end . "")
(subtype digest guess))
- (mime-parts
- (generate-head-function . nndoc-generate-mime-parts-head)
- (article-transform-function . nndoc-transform-mime-parts))
(nsmail
(article-begin . "^From - "))
(news
@@ -77,6 +74,9 @@ from the document.")
(mbox
(article-begin-function . nndoc-mbox-article-begin)
(body-end-function . nndoc-mbox-body-end))
+ (mime-parts
+ (generate-head-function . nndoc-generate-mime-parts-head)
+ (article-transform-function . nndoc-transform-mime-parts))
(babyl
(article-begin . "\^_\^L *\n")
(body-end . "\^_")
diff --git a/lisp/gnus/nnheader.el b/lisp/gnus/nnheader.el
index 9d22080cc75..b97fe5f8079 100644
--- a/lisp/gnus/nnheader.el
+++ b/lisp/gnus/nnheader.el
@@ -822,12 +822,16 @@ The first string in ARGS can be a format string."
(apply 'format args)))
nil)
-(defun nnheader-get-report (backend)
+(defun nnheader-get-report-string (backend)
"Get the most recent report from BACKEND."
(condition-case ()
- (nnheader-message 5 "%s" (symbol-value (intern (format "%s-status-string"
- backend))))
- (error (nnheader-message 5 ""))))
+ (format "%s" (symbol-value (intern (format "%s-status-string"
+ backend))))
+ (error "")))
+
+(defun nnheader-get-report (backend)
+ "Get the most recent report from BACKEND."
+ (nnheader-message 5 (nnheader-get-report-string backend)))
(defun nnheader-insert (format &rest args)
"Clear the communication buffer and insert FORMAT and ARGS into the buffer.
diff --git a/lisp/gnus/nnimap.el b/lisp/gnus/nnimap.el
index 000855db8da..f3cb77f5201 100644
--- a/lisp/gnus/nnimap.el
+++ b/lisp/gnus/nnimap.el
@@ -62,22 +62,23 @@ Values are `ssl', `network', `starttls' or `shell'.")
(defvoo nnimap-inbox nil
"The mail box where incoming mail arrives and should be split out of.")
+(defvoo nnimap-split-methods nil
+ "How mail is split.
+Uses the same syntax as nnmail-split-methods")
+
(defvoo nnimap-authenticator nil
"How nnimap authenticate itself to the server.
Possible choices are nil (use default methods) or `anonymous'.")
-(defvoo nnimap-fetch-partial-articles nil
- "If non-nil, nnimap will fetch partial articles.
-If t, nnimap will fetch only the first part. If a string, it
-will fetch all parts that have types that match that string. A
-likely value would be \"text/\" to automatically fetch all
-textual parts.")
-
(defvoo nnimap-expunge t
"If non-nil, expunge articles after deleting them.
This is always done if the server supports UID EXPUNGE, but it's
not done by default on servers that doesn't support that command.")
+(defvoo nnimap-streaming t
+ "If non-nil, try to use streaming commands with IMAP servers.
+Switching this off will make nnimap slower, but it helps with
+some servers.")
(defvoo nnimap-connection-alist nil)
@@ -110,8 +111,6 @@ not done by default on servers that doesn't support that command.")
(download "gnus-download")
(forward "gnus-forward")))
-(defvar nnimap-split-methods nil)
-
(defun nnimap-buffer ()
(nnimap-find-process-buffer nntp-server-buffer))
@@ -128,8 +127,7 @@ not done by default on servers that doesn't support that command.")
(nnimap-article-ranges (gnus-compress-sequence articles))
(format "(UID RFC822.SIZE BODYSTRUCTURE %s)"
(format
- (if (member "IMAP4REV1"
- (nnimap-capabilities nnimap-object))
+ (if (nnimap-ver4-p)
"BODY.PEEK[HEADER.FIELDS %s]"
"RFC822.HEADER.LINES %s")
(append '(Subject From Date Message-Id
@@ -273,42 +271,50 @@ not done by default on servers that doesn't support that command.")
(with-current-buffer (nnimap-make-process-buffer buffer)
(let* ((coding-system-for-read 'binary)
(coding-system-for-write 'binary)
+ (port nil)
(ports
(cond
((eq nnimap-stream 'network)
(open-network-stream
"*nnimap*" (current-buffer) nnimap-address
- (or nnimap-server-port
- (if (netrc-find-service-number "imap")
- "imap"
- "143")))
+ (setq port
+ (or nnimap-server-port
+ (if (netrc-find-service-number "imap")
+ "imap"
+ "143"))))
'("143" "imap"))
((eq nnimap-stream 'shell)
(nnimap-open-shell-stream
"*nnimap*" (current-buffer) nnimap-address
- (or nnimap-server-port "imap"))
+ (setq port (or nnimap-server-port "imap")))
'("imap"))
((eq nnimap-stream 'starttls)
(starttls-open-stream
"*nnimap*" (current-buffer) nnimap-address
- (or nnimap-server-port "imap"))
+ (setq port (or nnimap-server-port "imap")))
'("imap"))
((eq nnimap-stream 'ssl)
(open-tls-stream
"*nnimap*" (current-buffer) nnimap-address
- (or nnimap-server-port
- (if (netrc-find-service-number "imaps")
- "imaps"
- "993")))
+ (setq port
+ (or nnimap-server-port
+ (if (netrc-find-service-number "imaps")
+ "imaps"
+ "993"))))
'("143" "993" "imap" "imaps"))))
connection-result login-result credentials)
(setf (nnimap-process nnimap-object)
(get-buffer-process (current-buffer)))
- (when (and (nnimap-process nnimap-object)
- (memq (process-status (nnimap-process nnimap-object))
- '(open run)))
+ (if (not (and (nnimap-process nnimap-object)
+ (memq (process-status (nnimap-process nnimap-object))
+ '(open run))))
+ (nnheader-report 'nnimap "Unable to contact %s:%s via %s"
+ nnimap-address port nnimap-stream)
(gnus-set-process-query-on-exit-flag (nnimap-process nnimap-object) nil)
- (when (setq connection-result (nnimap-wait-for-connection))
+ (if (not (setq connection-result (nnimap-wait-for-connection)))
+ (nnheader-report 'nnimap
+ "%s" (buffer-substring
+ (point) (line-end-position)))
(when (eq nnimap-stream 'starttls)
(nnimap-command "STARTTLS")
(starttls-negotiate (nnimap-process nnimap-object)))
@@ -370,7 +376,7 @@ not done by default on servers that doesn't support that command.")
(deffoo nnimap-request-article (article &optional group server to-buffer)
(with-current-buffer nntp-server-buffer
(let ((result (nnimap-possibly-change-group group server))
- parts)
+ parts structure)
(when (stringp article)
(setq article (nnimap-find-article-by-message-id group article)))
(when (and result
@@ -378,36 +384,113 @@ not done by default on servers that doesn't support that command.")
(erase-buffer)
(with-current-buffer (nnimap-buffer)
(erase-buffer)
- (when nnimap-fetch-partial-articles
- (if (eq nnimap-fetch-partial-articles t)
+ (when gnus-fetch-partial-articles
+ (if (eq gnus-fetch-partial-articles t)
(setq parts '(1))
(nnimap-command "UID FETCH %d (BODYSTRUCTURE)" article)
(goto-char (point-min))
(when (re-search-forward "FETCH.*BODYSTRUCTURE" nil t)
- (let ((structure (ignore-errors (read (current-buffer)))))
- (setq parts (nnimap-find-wanted-parts structure))))))
- (setq result
- (nnimap-command
- (if (member "IMAP4REV1" (nnimap-capabilities nnimap-object))
- "UID FETCH %d BODY.PEEK[]"
- "UID FETCH %d RFC822.PEEK")
- article))
- ;; Check that we really got an article.
- (goto-char (point-min))
- (unless (looking-at "\\* [0-9]+ FETCH")
- (setq result nil)))
- (let ((buffer (nnimap-find-process-buffer (current-buffer))))
- (when (car result)
- (with-current-buffer (or to-buffer nntp-server-buffer)
- (insert-buffer-substring buffer)
- (goto-char (point-min))
- (let ((bytes (nnimap-get-length)))
- (delete-region (line-beginning-position)
- (progn (forward-line 1) (point)))
- (goto-char (+ (point) bytes))
- (delete-region (point) (point-max))
- (nnheader-ms-strip-cr))
- (cons group article))))))))
+ (setq structure (ignore-errors (read (current-buffer)))
+ parts (nnimap-find-wanted-parts structure)))))
+ (when (if parts
+ (nnimap-get-partial-article article parts structure)
+ (nnimap-get-whole-article article))
+ (let ((buffer (current-buffer)))
+ (with-current-buffer (or to-buffer nntp-server-buffer)
+ (erase-buffer)
+ (insert-buffer-substring buffer)
+ (nnheader-ms-strip-cr)
+ (cons group article)))))))))
+
+(defun nnimap-get-whole-article (article)
+ (let ((result
+ (nnimap-command
+ (if (nnimap-ver4-p)
+ "UID FETCH %d BODY.PEEK[]"
+ "UID FETCH %d RFC822.PEEK")
+ article)))
+ ;; Check that we really got an article.
+ (goto-char (point-min))
+ (unless (looking-at "\\* [0-9]+ FETCH")
+ (setq result nil))
+ (when result
+ (goto-char (point-min))
+ (let ((bytes (nnimap-get-length)))
+ (delete-region (line-beginning-position)
+ (progn (forward-line 1) (point)))
+ (goto-char (+ (point) bytes))
+ (delete-region (point) (point-max)))
+ t)))
+
+(defun nnimap-ver4-p ()
+ (member "IMAP4REV1" (nnimap-capabilities nnimap-object)))
+
+(defun nnimap-get-partial-article (article parts structure)
+ (let ((result
+ (nnimap-command
+ "UID FETCH %d (%s %s)"
+ article
+ (if (nnimap-ver4-p)
+ "BODY.PEEK[HEADER]"
+ "RFC822.HEADER")
+ (if (nnimap-ver4-p)
+ (mapconcat (lambda (part)
+ (format "BODY.PEEK[%s]" part))
+ parts " ")
+ (mapconcat (lambda (part)
+ (format "RFC822.PEEK[%s]" part))
+ parts " ")))))
+ (when result
+ (nnimap-convert-partial-article structure))))
+
+(defun nnimap-convert-partial-article (structure)
+ ;; First just skip past the headers.
+ (goto-char (point-min))
+ (let ((bytes (nnimap-get-length))
+ id parts)
+ ;; Delete "FETCH" line.
+ (delete-region (line-beginning-position)
+ (progn (forward-line 1) (point)))
+ (goto-char (+ (point) bytes))
+ ;; Collect all the body parts.
+ (while (looking-at ".*BODY\\[\\([.0-9]+\\)\\]")
+ (setq id (match-string 1)
+ bytes (nnimap-get-length))
+ (beginning-of-line)
+ (delete-region (point) (progn (forward-line 1) (point)))
+ (push (list id (buffer-substring (point) (+ (point) bytes)))
+ parts)
+ (delete-region (point) (+ (point) bytes)))
+ ;; Delete trailing junk.
+ (delete-region (point) (point-max))
+ ;; Now insert all the parts again where they fit in the structure.
+ (nnimap-insert-partial-structure structure parts)
+ t))
+
+(defun nnimap-insert-partial-structure (structure parts &optional subp)
+ (let ((type (car (last structure 4)))
+ (boundary (cadr (member "BOUNDARY" (car (last structure 3))))))
+ (when subp
+ (insert (format "Content-type: multipart/%s; boundary=%S\n\n"
+ (downcase type) boundary)))
+ (while (not (stringp (car structure)))
+ (insert "\n--" boundary "\n")
+ (if (consp (caar structure))
+ (nnimap-insert-partial-structure (pop structure) parts t)
+ (let ((bit (pop structure)))
+ (insert (format "Content-type: %s/%s"
+ (downcase (nth 0 bit))
+ (downcase (nth 1 bit))))
+ (if (member "CHARSET" (nth 2 bit))
+ (insert (format
+ "; charset=%S\n" (cadr (member "CHARSET" (nth 2 bit)))))
+ (insert "\n"))
+ (insert (format "Content-transfer-encoding: %s\n"
+ (nth 5 bit)))
+ (insert "\n")
+ (when (assoc (nth 9 bit) parts)
+ (insert (cadr (assoc (nth 9 bit) parts)))))))
+ (insert "\n--" boundary "--\n")))
(defun nnimap-find-wanted-parts (structure)
(message-flatten-list (nnimap-find-wanted-parts-1 structure "")))
@@ -423,13 +506,14 @@ not done by default on servers that doesn't support that command.")
(number-to-string num)
(format "%s.%s" prefix num)))
parts)
- (let ((type (format "%s/%s" (nth 0 sub) (nth 1 sub))))
- (when (string-match nnimap-fetch-partial-articles type)
- (push (if (string= prefix "")
+ (let ((type (format "%s/%s" (nth 0 sub) (nth 1 sub)))
+ (id (if (string= prefix "")
(number-to-string num)
- (format "%s.%s" prefix num))
- parts)))
- (incf num))))
+ (format "%s.%s" prefix num))))
+ (setcar (nthcdr 9 sub) id)
+ (when (string-match gnus-fetch-partial-articles type)
+ (push id parts))))
+ (incf num)))
(nreverse parts)))
(deffoo nnimap-request-group (group &optional server dont-check info)
@@ -777,7 +861,12 @@ not done by default on servers that doesn't support that command.")
(nnimap-send-command "UID FETCH %d:* FLAGS" start)
start
(car elem))
- sequences))))
+ sequences)))
+ ;; Some servers apparently can't have many outstanding
+ ;; commands, so throttle them.
+ (when (and (not nnimap-streaming)
+ (car sequences))
+ (nnimap-wait-for-response (caar sequences))))
sequences))))
(deffoo nnimap-finish-retrieve-group-infos (server infos sequences)
@@ -785,26 +874,26 @@ not done by default on servers that doesn't support that command.")
(nnimap-possibly-change-group nil server))
(with-current-buffer (nnimap-buffer)
;; Wait for the final data to trickle in.
- (nnimap-wait-for-response (cadar sequences))
- ;; Now we should have all the data we need, no matter whether
- ;; we're QRESYNCING, fetching all the flags from scratch, or
- ;; just fetching the last 100 flags per group.
- (nnimap-update-infos (nnimap-flags-to-marks
- (nnimap-parse-flags
- (nreverse sequences)))
- infos)
- ;; Finally, just return something resembling an active file in
- ;; the nntp buffer, so that the agent can save the info, too.
- (with-current-buffer nntp-server-buffer
- (erase-buffer)
- (dolist (info infos)
- (let* ((group (gnus-info-group info))
- (active (gnus-active group)))
- (when active
- (insert (format "%S %d %d y\n"
- (gnus-group-real-name group)
- (cdr active)
- (car active))))))))))
+ (when (nnimap-wait-for-response (cadar sequences))
+ ;; Now we should have all the data we need, no matter whether
+ ;; we're QRESYNCING, fetching all the flags from scratch, or
+ ;; just fetching the last 100 flags per group.
+ (nnimap-update-infos (nnimap-flags-to-marks
+ (nnimap-parse-flags
+ (nreverse sequences)))
+ infos)
+ ;; Finally, just return something resembling an active file in
+ ;; the nntp buffer, so that the agent can save the info, too.
+ (with-current-buffer nntp-server-buffer
+ (erase-buffer)
+ (dolist (info infos)
+ (let* ((group (gnus-info-group info))
+ (active (gnus-active group)))
+ (when active
+ (insert (format "%S %d %d y\n"
+ (gnus-group-real-name group)
+ (cdr active)
+ (car active)))))))))))
(defun nnimap-update-infos (flags infos)
(dolist (info infos)
@@ -1045,17 +1134,22 @@ not done by default on servers that doesn't support that command.")
(match-string 1))))
(defun nnimap-wait-for-response (sequence &optional messagep)
- (let ((process (get-buffer-process (current-buffer))))
+ (let ((process (get-buffer-process (current-buffer)))
+ openp)
(goto-char (point-max))
- (while (and (memq (process-status process)
- '(open run))
- (not (re-search-backward (format "^%d .*\n" sequence)
- (max (point-min) (- (point) 500))
- t)))
+ (while (and (setq openp (memq (process-status process)
+ '(open run)))
+ (not (re-search-backward
+ (format "^%d .*\n" sequence)
+ (if nnimap-streaming
+ (max (point-min) (- (point) 500))
+ (point-min))
+ t)))
(when messagep
(message "Read %dKB" (/ (buffer-size) 1000)))
(nnheader-accept-process-output process)
- (goto-char (point-max)))))
+ (goto-char (point-max)))
+ openp))
(defun nnimap-parse-response ()
(let ((lines (split-string (nnimap-last-response-string) "\r\n" t))
@@ -1129,8 +1223,7 @@ not done by default on servers that doesn't support that command.")
(nnimap-article-ranges articles)
(format "(UID %s%s)"
(format
- (if (member "IMAP4REV1"
- (nnimap-capabilities nnimap-object))
+ (if (nnimap-ver4-p)
"BODY.PEEK[HEADER] BODY.PEEK"
"RFC822.PEEK"))
(if nnimap-split-download-body-default